diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryClientService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryClientService.java index 7427926..02139d2 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryClientService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryClientService.java @@ -56,6 +56,9 @@ import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.ContainerReport; import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.exceptions.ApplicationAttemptNotFoundException; +import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException; +import org.apache.hadoop.yarn.exceptions.ContainerNotFoundException; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.ipc.YarnRPC; import org.apache.hadoop.yarn.server.timeline.security.authorize.TimelinePolicyProvider; @@ -145,9 +148,16 @@ public GetApplicationAttemptReportResponse getApplicationAttemptReport( IOException { ApplicationAttemptId appAttemptId = request.getApplicationAttemptId(); try { + ApplicationAttemptReport attemptReport = history + .getApplicationAttempt(appAttemptId); + if (attemptReport == null) { + // If there is no such attempt, throw + // ApplicationAttemptNotFoundException and let client to handle. + throw new ApplicationAttemptNotFoundException("Application attempt " + + "with id '" + appAttemptId + "' doesn't exist in timeline store."); + } GetApplicationAttemptReportResponse response = - GetApplicationAttemptReportResponse.newInstance(history - .getApplicationAttempt(appAttemptId)); + GetApplicationAttemptReportResponse.newInstance(attemptReport); return response; } catch (IOException e) { LOG.error(e.getMessage(), e); @@ -170,9 +180,15 @@ public GetApplicationReportResponse getApplicationReport( GetApplicationReportRequest request) throws YarnException, IOException { ApplicationId applicationId = request.getApplicationId(); try { + ApplicationReport appReport = history.getApplication(applicationId); + if (appReport == null) { + // If there is no such application, throw + // ApplicationNotFoundException and let the client to handle. + throw new ApplicationNotFoundException("Application with id '" + + applicationId + "' doesn't exist in timeline store."); + } GetApplicationReportResponse response = - GetApplicationReportResponse.newInstance(history - .getApplication(applicationId)); + GetApplicationReportResponse.newInstance(appReport); return response; } catch (IOException e) { LOG.error(e.getMessage(), e); @@ -195,9 +211,15 @@ public GetContainerReportResponse getContainerReport( GetContainerReportRequest request) throws YarnException, IOException { ContainerId containerId = request.getContainerId(); try { + ContainerReport containerReport = history.getContainer(containerId); + if (containerReport == null) { + // If there is no such container, throw + // ContainerNotFoundException and let client to handle. + throw new ContainerNotFoundException("Container with id '" + + containerId + "' doesn't exist in timeline store."); + } GetContainerReportResponse response = - GetContainerReportResponse.newInstance(history - .getContainer(containerId)); + GetContainerReportResponse.newInstance(containerReport); return response; } catch (IOException e) { LOG.error(e.getMessage(), e); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryManagerOnTimelineStore.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryManagerOnTimelineStore.java index d3e7b5c..bf5e1c9 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryManagerOnTimelineStore.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/main/java/org/apache/hadoop/yarn/server/applicationhistoryservice/ApplicationHistoryManagerOnTimelineStore.java @@ -51,9 +51,6 @@ import org.apache.hadoop.yarn.api.records.timeline.TimelineEntity; import org.apache.hadoop.yarn.api.records.timeline.TimelineEvent; import org.apache.hadoop.yarn.conf.YarnConfiguration; -import org.apache.hadoop.yarn.exceptions.ApplicationAttemptNotFoundException; -import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException; -import org.apache.hadoop.yarn.exceptions.ContainerNotFoundException; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.server.metrics.AppAttemptMetricsConstants; import org.apache.hadoop.yarn.server.metrics.ApplicationMetricsConstants; @@ -102,7 +99,15 @@ protected void serviceInit(Configuration conf) throws Exception { @Override public ApplicationReport getApplication(ApplicationId appId) throws YarnException, IOException { - return getApplication(appId, ApplicationReportField.ALL).appReport; + ApplicationReportExt report = + getApplication(appId, ApplicationReportField.ALL); + if (report != null) { + ApplicationReport appReport = report.appReport; + if (appReport != null) { + return appReport; + } + } + return null; } @Override @@ -135,6 +140,9 @@ public ApplicationReport getApplication(ApplicationId appId) throws YarnException, IOException { ApplicationReportExt app = getApplication( appId, ApplicationReportField.USER_AND_ACLS); + if (app == null) { + return null; + } checkAccess(app); TimelineEntities entities = timelineDataManager.getEntities( AppAttemptMetricsConstants.ENTITY_TYPE, @@ -166,6 +174,9 @@ private ApplicationAttemptReport getApplicationAttempt( ApplicationReportExt app = getApplication( appAttemptId.getApplicationId(), ApplicationReportField.USER_AND_ACLS); + if (app == null) { + return null; + } checkAccess(app); } TimelineEntity entity = timelineDataManager.getEntity( @@ -173,9 +184,11 @@ private ApplicationAttemptReport getApplicationAttempt( appAttemptId.toString(), EnumSet.allOf(Field.class), UserGroupInformation.getLoginUser()); if (entity == null) { - throw new ApplicationAttemptNotFoundException( - "The entity for application attempt " + appAttemptId + - " doesn't exist in the timeline store"); + if(LOG.isDebugEnabled()) { + LOG.debug("The entity for application attempt " + appAttemptId + + " doesn't exist in the timeline store"); + } + return null; } else { return convertToApplicationAttemptReport(entity); } @@ -187,15 +200,20 @@ public ContainerReport getContainer(ContainerId containerId) ApplicationReportExt app = getApplication( containerId.getApplicationAttemptId().getApplicationId(), ApplicationReportField.USER_AND_ACLS); + if (app == null) { + return null; + } checkAccess(app); TimelineEntity entity = timelineDataManager.getEntity( ContainerMetricsConstants.ENTITY_TYPE, containerId.toString(), EnumSet.allOf(Field.class), UserGroupInformation.getLoginUser()); if (entity == null) { - throw new ContainerNotFoundException( - "The entity for container " + containerId + - " doesn't exist in the timeline store"); + if(LOG.isDebugEnabled()) { + LOG.debug("The entity for container " + containerId + + " doesn't exist in the timeline store"); + } + return null; } else { return convertToContainerReport( entity, serverHttpAddress, app.appReport.getUser()); @@ -215,6 +233,9 @@ public ContainerReport getAMContainer(ApplicationAttemptId appAttemptId) ApplicationAttemptId appAttemptId) throws YarnException, IOException { ApplicationReportExt app = getApplication( appAttemptId.getApplicationId(), ApplicationReportField.USER_AND_ACLS); + if (app == null) { + return null; + } checkAccess(app); TimelineEntities entities = timelineDataManager.getEntities( ContainerMetricsConstants.ENTITY_TYPE, @@ -539,6 +560,9 @@ private ApplicationReportExt generateApplicationReport(TimelineEntity entity, return app; } try { + if(app == null) { + return null; + } checkAccess(app); if (app.appReport.getCurrentApplicationAttemptId() != null) { ApplicationAttemptReport appAttempt = getApplicationAttempt( @@ -548,7 +572,7 @@ private ApplicationReportExt generateApplicationReport(TimelineEntity entity, app.appReport.setTrackingUrl(appAttempt.getTrackingUrl()); app.appReport.setOriginalTrackingUrl(appAttempt.getOriginalTrackingUrl()); } - } catch (AuthorizationException | ApplicationAttemptNotFoundException e) { + } catch (AuthorizationException e) { // AuthorizationException is thrown because the user doesn't have access // It's possible that the app is finished before the first attempt is created. app.appReport.setDiagnostics(null); @@ -583,8 +607,11 @@ private ApplicationReportExt getApplication(ApplicationId appId, appId.toString(), EnumSet.allOf(Field.class), UserGroupInformation.getLoginUser()); if (entity == null) { - throw new ApplicationNotFoundException("The entity for application " + - appId + " doesn't exist in the timeline store"); + if(LOG.isDebugEnabled()) { + LOG.debug("The entity for application " + + appId + " doesn't exist in the timeline store"); + } + return null; } else { return generateApplicationReport(entity, field); } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java index ad03718..5abb9a2 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java @@ -41,6 +41,9 @@ import org.apache.hadoop.yarn.api.records.ContainerId; import org.apache.hadoop.yarn.api.records.ContainerReport; import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.exceptions.ApplicationAttemptNotFoundException; +import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException; +import org.apache.hadoop.yarn.exceptions.ContainerNotFoundException; import org.apache.hadoop.yarn.exceptions.YarnException; import org.apache.hadoop.yarn.server.security.ApplicationACLsManager; import org.apache.hadoop.yarn.server.timeline.TimelineDataManager; @@ -54,12 +57,13 @@ private static ApplicationHistoryClientService clientService; private static TimelineDataManager dataManager; + private final static int MAX_APPS = 2; @BeforeClass public static void setup() throws Exception { Configuration conf = new YarnConfiguration(); TimelineStore store = - TestApplicationHistoryManagerOnTimelineStore.createStore(2); + TestApplicationHistoryManagerOnTimelineStore.createStore(MAX_APPS); TimelineACLsManager aclsManager = new TimelineACLsManager(conf); dataManager = new TimelineDataManager(store, aclsManager); @@ -72,6 +76,71 @@ public static void setup() throws Exception { } @Test + public void testApplicationNotFound() throws IOException, YarnException { + ApplicationId appId = null; + appId = ApplicationId.newInstance(0, MAX_APPS + 1); + GetApplicationReportRequest request = + GetApplicationReportRequest.newInstance(appId); + try { + @SuppressWarnings("unused") + GetApplicationReportResponse response = + clientService.getApplicationReport(request); + Assert.fail("Exception should have been thrown before we reach here."); + } catch (ApplicationNotFoundException e) { + //This exception is expected. + Assert.assertTrue(e.getMessage(). + contains("Application with id") && e.getMessage(). + contains("doesn't exist in timeline store.")); + } catch (Exception e) { + Assert.fail("Undesired exception caught"); + } + } + + @Test + public void testApplicationAttemptNotFound() throws IOException, YarnException { + ApplicationId appId = ApplicationId.newInstance(0, 1); + ApplicationAttemptId appAttemptId = + ApplicationAttemptId.newInstance(appId, MAX_APPS + 1); + GetApplicationAttemptReportRequest request = + GetApplicationAttemptReportRequest.newInstance(appAttemptId); + try { + @SuppressWarnings("unused") + GetApplicationAttemptReportResponse response = + clientService.getApplicationAttemptReport(request); + Assert.fail("Exception should have been thrown before we reach here."); + } catch (ApplicationAttemptNotFoundException e) { + //This Exception is expected + System.out.println(e.getMessage()); + Assert.assertTrue( e.getMessage().contains("Application attempt with id") + && e.getMessage().contains("doesn't exist in timeline store.")); + } catch (Exception e) { + Assert.fail("Undesired exception caught"); + } + } + + @Test + public void testContainerNotFound() throws IOException, YarnException { + ApplicationId appId = ApplicationId.newInstance(0, 1); + ApplicationAttemptId appAttemptId = + ApplicationAttemptId.newInstance(appId, 1); + ContainerId containerId = ContainerId.newContainerId(appAttemptId, + MAX_APPS + 1); + GetContainerReportRequest request = + GetContainerReportRequest.newInstance(containerId); + try { + @SuppressWarnings("unused") + GetContainerReportResponse response = + clientService.getContainerReport(request); + } catch (ContainerNotFoundException e) { + //This exception is expected + Assert.assertTrue(e.getMessage().contains("Container with id") && + e.getMessage().contains("doesn't exist in timeline store.")); + } catch (Exception e) { + Assert.fail("Undesired exception caught"); + } + } + + @Test public void testApplicationReport() throws IOException, YarnException { ApplicationId appId = null; appId = ApplicationId.newInstance(0, 1); diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java index 613df72..b5ff6a4 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java @@ -82,12 +82,13 @@ private static ApplicationHistoryClientService historyClientService; private static final String[] USERS = new String[] { "foo" , "bar" }; + private static final int MAX_APPS = 5; @BeforeClass public static void setupClass() throws Exception { Configuration conf = new YarnConfiguration(); TimelineStore store = - TestApplicationHistoryManagerOnTimelineStore.createStore(5); + TestApplicationHistoryManagerOnTimelineStore.createStore(MAX_APPS); TimelineACLsManager aclsManager = new TimelineACLsManager(conf); TimelineDataManager dataManager = new TimelineDataManager(store, aclsManager); @@ -165,6 +166,66 @@ public TestAHSWebServices(int round) { } @Test + public void testInvalidApp() { + ApplicationId appId = ApplicationId.newInstance(0, MAX_APPS + 1); + WebResource r = resource(); + ClientResponse response = + r.path("ws").path("v1").path("applicationhistory").path("apps") + .path(appId.toString()) + .queryParam("user.name", USERS[round]) + .accept(MediaType.APPLICATION_JSON) + .get(ClientResponse.class); + assertEquals("404 not found expected", Status.NOT_FOUND, + response.getClientResponseStatus()); + } + + @Test + public void testInvalidAttempt() { + ApplicationId appId = ApplicationId.newInstance(0, 1); + ApplicationAttemptId appAttemptId = + ApplicationAttemptId.newInstance(appId, MAX_APPS + 1); + WebResource r = resource(); + ClientResponse response = + r.path("ws").path("v1").path("applicationhistory").path("apps") + .path(appId.toString()).path("appattempts") + .path(appAttemptId.toString()) + .queryParam("user.name", USERS[round]) + .accept(MediaType.APPLICATION_JSON) + .get(ClientResponse.class); + if (round == 1) { + assertEquals(Status.FORBIDDEN, response.getClientResponseStatus()); + return; + } + assertEquals("404 not found expected", Status.NOT_FOUND, + response.getClientResponseStatus()); + } + + @Test + public void testInvalidContainer() throws Exception { + ApplicationId appId = ApplicationId.newInstance(0, 1); + ApplicationAttemptId appAttemptId = + ApplicationAttemptId.newInstance(appId, 1); + ContainerId containerId = ContainerId.newContainerId(appAttemptId, + MAX_APPS + 1); + WebResource r = resource(); + ClientResponse response = + r.path("ws").path("v1").path("applicationhistory").path("apps") + .path(appId.toString()).path("appattempts") + .path(appAttemptId.toString()).path("containers") + .path(containerId.toString()) + .queryParam("user.name", USERS[round]) + .accept(MediaType.APPLICATION_JSON) + .get(ClientResponse.class); + if (round == 1) { + assertEquals( + Status.FORBIDDEN, response.getClientResponseStatus()); + return; + } + assertEquals("404 not found expected", Status.NOT_FOUND, + response.getClientResponseStatus()); + } + + @Test public void testInvalidUri() throws JSONException, Exception { WebResource r = resource(); String responseStr = ""; diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java index 8404719..a04aafa 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java @@ -47,6 +47,9 @@ import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetContainerReportRequest; import org.apache.hadoop.yarn.api.protocolrecords.GetContainersRequest; +import org.apache.hadoop.yarn.exceptions.ApplicationAttemptNotFoundException; +import org.apache.hadoop.yarn.exceptions.ApplicationNotFoundException; +import org.apache.hadoop.yarn.exceptions.ContainerNotFoundException; import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptInfo; import org.apache.hadoop.yarn.server.webapp.dao.AppAttemptsInfo; import org.apache.hadoop.yarn.server.webapp.dao.AppInfo; @@ -477,6 +480,11 @@ protected static UserGroupInformation getUser(HttpServletRequest req) { private static void rewrapAndThrowException(Exception e) { if (e instanceof UndeclaredThrowableException) { + if (e.getCause() instanceof ApplicationNotFoundException || + e.getCause() instanceof ApplicationAttemptNotFoundException || + e.getCause() instanceof ContainerNotFoundException) { + throw new NotFoundException(e.getCause()); + } if (e.getCause() instanceof AuthorizationException) { throw new ForbiddenException(e.getCause()); } else {