From 0943e0f5a81e466c94e12277a2442edb0c9cded4 Mon Sep 17 00:00:00 2001 From: Xuan Date: Sun, 31 May 2015 15:41:13 -0700 Subject: [PATCH] YARN-2900. Application (Attempt and Container) Not Found in AHS results in Internal Server Error (500). Contributed by Zhijie Shen and Mit Desai --- hadoop-yarn-project/CHANGES.txt | 3 + .../TestApplicationHistoryClientService.java | 70 ++++++++++++++++++- .../webapp/TestAHSWebServices.java | 63 ++++++++++++++++- .../yarn/server/webapp/WebServices.java | 27 ++++--- 4 files changed, 151 insertions(+), 12 deletions(-) diff --git a/hadoop-yarn-project/CHANGES.txt b/hadoop-yarn-project/CHANGES.txt index 74334d2ac51..1f2dde5bde5 100644 --- a/hadoop-yarn-project/CHANGES.txt +++ b/hadoop-yarn-project/CHANGES.txt @@ -139,6 +139,9 @@ Release 2.7.1 - UNRELEASED YARN-3686. CapacityScheduler should trim default_node_label_expression. (Sunil G via wangda) + YARN-2900. Application (Attempt and Container) Not Found in AHS results + in Internal Server Error (500). (Zhijie Shen and Mit Desai via xgong) + Release 2.7.0 - 2015-04-20 INCOMPATIBLE CHANGES diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java index d03b26dc083..ba701a130d0 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/TestApplicationHistoryClientService.java +++ b/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.ApplicationReport; 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; @@ -53,12 +56,13 @@ import org.junit.Test; public class TestApplicationHistoryClientService { private static ApplicationHistoryClientService clientService; + 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); TimelineDataManager dataManager = new TimelineDataManager(store, aclsManager); @@ -70,6 +74,70 @@ public class TestApplicationHistoryClientService { clientService = new ApplicationHistoryClientService(historyManager); } + @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( + "doesn't exist in the 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( + "doesn't exist in the 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( + "doesn't exist in the timeline store")); + } catch (Exception e) { + Assert.fail("Undesired exception caught"); + } + } + @Test public void testApplicationReport() throws IOException, YarnException { ApplicationId appId = null; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java b/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 913b80dd062..80ffa032f34 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-applicationhistoryservice/src/test/java/org/apache/hadoop/yarn/server/applicationhistoryservice/webapp/TestAHSWebServices.java @@ -79,12 +79,13 @@ public class TestAHSWebServices extends JerseyTestBase { 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); @@ -161,6 +162,66 @@ public class TestAHSWebServices extends JerseyTestBase { this.round = 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(); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java index 909bf1d022c..d0ccd74110c 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-common/src/main/java/org/apache/hadoop/yarn/server/webapp/WebServices.java +++ b/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.GetApplicationReportRequest; 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; @@ -484,17 +487,21 @@ public class WebServices { private static void rewrapAndThrowException(Exception e) { if (e instanceof UndeclaredThrowableException) { - if (e.getCause() instanceof AuthorizationException) { - throw new ForbiddenException(e.getCause()); - } else { - throw new WebApplicationException(e.getCause()); - } + rewrapAndThrowThrowable(e.getCause()); } else { - if (e instanceof AuthorizationException) { - throw new ForbiddenException(e); - } else { - throw new WebApplicationException(e); - } + rewrapAndThrowThrowable(e); + } + } + + private static void rewrapAndThrowThrowable(Throwable t) { + if (t instanceof AuthorizationException) { + throw new ForbiddenException(t); + } else if (t instanceof ApplicationNotFoundException || + t instanceof ApplicationAttemptNotFoundException || + t instanceof ContainerNotFoundException) { + throw new NotFoundException(t); + } else { + throw new WebApplicationException(t); } }