diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java index 56eba34..33d7761 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java @@ -19,6 +19,7 @@ package org.apache.hadoop.yarn.server.resourcemanager.webapp; import java.io.IOException; +import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.Collection; import java.util.EnumSet; @@ -31,19 +32,27 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.Consumes; import javax.ws.rs.GET; +import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.security.UserGroupInformation; +import org.apache.hadoop.security.authorize.AuthorizationException; import org.apache.hadoop.yarn.api.protocolrecords.GetApplicationsRequest; +import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationRequest; +import org.apache.hadoop.yarn.api.protocolrecords.KillApplicationResponse; import org.apache.hadoop.yarn.api.records.ApplicationAccessType; import org.apache.hadoop.yarn.api.records.ApplicationId; import org.apache.hadoop.yarn.api.records.ApplicationReport; @@ -56,6 +65,8 @@ import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; import org.apache.hadoop.yarn.factories.RecordFactory; import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider; +import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger; +import org.apache.hadoop.yarn.server.resourcemanager.RMAuditLogger.AuditConstants; import org.apache.hadoop.yarn.server.resourcemanager.RMServerUtils; import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; import org.apache.hadoop.yarn.server.resourcemanager.rmapp.RMApp; @@ -70,6 +81,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppAttemptsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppState; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ApplicationStatisticsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppsInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.CapacitySchedulerInfo; @@ -584,4 +596,184 @@ public AppAttemptsInfo getAppAttempts(@PathParam("appid") String appId) { return appAttemptsInfo; } + + @GET + @Path("/apps/{appid}/state") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public AppState getAppState(@Context HttpServletRequest hsr, + @PathParam("appid") String appId) throws AuthorizationException { + init(); + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr); + String userName = ""; + if (callerUGI != null) { + userName = callerUGI.getUserName(); + } + RMApp app = null; + try { + app = getRMAppForAppId(appId); + } catch (NotFoundException e) { + RMAuditLogger.logFailure(userName, AuditConstants.KILL_APP_REQUEST, + "UNKNOWN", "RMWebService", + "Trying to get state of an absent application " + appId); + throw e; + } + + AppState ret = new AppState(); + ret.setState(app.getState().toString()); + + return ret; + } + + // can't return POJO because we can't control the status code + // it's always set to 200 when we need to allow it to be set + // to 202 + + @PUT + @Path("/apps/{appid}/state") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response updateAppState(AppState targetState, + @Context HttpServletRequest hsr, @PathParam("appid") String appId) + throws AuthorizationException, YarnException, InterruptedException, + IOException { + + init(); + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr); + if (callerUGI == null) { + String msg = "Unable to obtain user name, user not authenticated"; + throw new AuthorizationException(msg); + } + + String userName = callerUGI.getUserName(); + RMApp app = null; + try { + app = getRMAppForAppId(appId); + } catch (NotFoundException e) { + RMAuditLogger.logFailure(userName, AuditConstants.KILL_APP_REQUEST, + "UNKNOWN", "RMWebService", "Trying to kill/move an absent application " + + appId); + throw e; + } + + if (!app.getState().toString().equals(targetState.getState())) { + // user is attempting to change state. right we only + // allow users to kill the app + + if (targetState.getState().equals(YarnApplicationState.KILLED.toString())) { + return killApp(app, callerUGI, hsr); + } + throw new BadRequestException("Only '" + + YarnApplicationState.KILLED.toString() + + "' is allowed as a target state."); + } + + AppInfo ret = + new AppInfo(app, hasAccess(app, hsr), hsr.getScheme() + "://"); + return Response.status(Status.OK).entity(ret).build(); + } + + protected Response killApp(RMApp app, UserGroupInformation callerUGI, + HttpServletRequest hsr) throws IOException, InterruptedException { + + if (app == null) { + throw new IllegalArgumentException("app cannot be null"); + } + String userName = callerUGI.getUserName(); + if (!hasAppAcess(app, callerUGI, ApplicationAccessType.MODIFY_APP)) { + String appId = app.getApplicationId().toString(); + String msg = + "Unauthorized attempt to kill appid " + appId + " by remote user " + + userName; + RMAuditLogger.logFailure(userName, AuditConstants.KILL_APP_REQUEST, + "UNKNOWN", "RMWebService", "Unauthorized attempt to kill appid " + + appId); + return Response.status(Status.FORBIDDEN).entity(msg).build(); + } + + final ApplicationId appid = app.getApplicationId(); + KillApplicationResponse resp = + callerUGI + .doAs(new PrivilegedExceptionAction() { + @Override + public KillApplicationResponse run() throws IOException, + YarnException { + KillApplicationRequest req = + KillApplicationRequest.newInstance(appid); + return rm.getClientRMService().forceKillApplication(req); + } + }); + + AppInfo ret = + new AppInfo(app, hasAppAcess(app, callerUGI, + ApplicationAccessType.MODIFY_APP), hsr.getScheme() + "://"); + + if (resp.getIsKillCompleted()) { + RMAuditLogger.logSuccess(userName, AuditConstants.KILL_APP_REQUEST, + "RMWebService", app.getApplicationId()); + } else { + int endIndex = + hsr.getRequestURL().toString().length() - "/state".length(); + String appURL = hsr.getRequestURL().toString().substring(0, endIndex); + return Response.status(Status.ACCEPTED).entity(ret) + .header(HttpHeaders.LOCATION, appURL).build(); + } + + return Response.status(Status.OK).entity(ret).build(); + } + + private RMApp getRMAppForAppId(String appId) { + + if (appId == null || appId.isEmpty()) { + throw new NotFoundException("appId, " + appId + ", is empty or null"); + } + ApplicationId id; + try { + id = ConverterUtils.toApplicationId(recordFactory, appId); + } catch (NumberFormatException e) { + throw new NotFoundException("appId is invalid"); + } + if (id == null) { + throw new NotFoundException("appId is invalid"); + } + RMApp app = rm.getRMContext().getRMApps().get(id); + if (app == null) { + throw new NotFoundException("app with id: " + appId + " not found"); + } + return app; + } + + private UserGroupInformation getCallerUserGroupInformation( + HttpServletRequest hsr) { + + String remoteUser = hsr.getRemoteUser(); + UserGroupInformation callerUGI = null; + if (remoteUser != null) { + callerUGI = UserGroupInformation.createRemoteUser(remoteUser); + } + + return callerUGI; + } + + protected Boolean hasAppAcess(RMApp app, UserGroupInformation callerUGI, + ApplicationAccessType type) { + if (callerUGI != null) { + if (!this.rm.getApplicationACLsManager().checkAccess(callerUGI, type, + app.getUser(), app.getApplicationId())) { + return false; + } + } + return true; + } + + protected Boolean hasQueueAcess(RMApp app, UserGroupInformation callerUGI, + QueueACL type) { + if (callerUGI != null) { + if (!this.rm.getQueueACLsManager().checkAccess(callerUGI, type, + app.getQueue())) { + return false; + } + } + return true; + } + } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java index 11f798d..49dd0cc 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppInfo.java @@ -253,5 +253,113 @@ public int getAllocatedMB() { public int getAllocatedVCores() { return this.allocatedVCores; } + + public void setAppIdNum(String appIdNum) { + this.appIdNum = appIdNum; + } + + public void setTrackingUrlIsNotReady(boolean trackingUrlIsNotReady) { + this.trackingUrlIsNotReady = trackingUrlIsNotReady; + } + + public void setTrackingUrlPretty(String trackingUrlPretty) { + this.trackingUrlPretty = trackingUrlPretty; + } + + public void setAmContainerLogsExist(boolean amContainerLogsExist) { + this.amContainerLogsExist = amContainerLogsExist; + } + + public void setApplicationId(ApplicationId applicationId) { + this.applicationId = applicationId; + } + + public void setSchemePrefix(String schemePrefix) { + this.schemePrefix = schemePrefix; + } + + public void setId(String id) { + this.id = id; + } + + public void setUser(String user) { + this.user = user; + } + + public void setName(String name) { + this.name = name; + } + + public void setQueue(String queue) { + this.queue = queue; + } + + public void setState(YarnApplicationState state) { + this.state = state; + } + + public void setFinalStatus(FinalApplicationStatus finalStatus) { + this.finalStatus = finalStatus; + } + + public void setProgress(float progress) { + this.progress = progress; + } + + public void setTrackingUI(String trackingUI) { + this.trackingUI = trackingUI; + } + + public void setTrackingUrl(String trackingUrl) { + this.trackingUrl = trackingUrl; + } + + public void setDiagnostics(String diagnostics) { + this.diagnostics = diagnostics; + } + + public void setClusterId(long clusterId) { + this.clusterId = clusterId; + } + + public void setApplicationType(String applicationType) { + this.applicationType = applicationType; + } + + public void setApplicationTags(String applicationTags) { + this.applicationTags = applicationTags; + } + + public void setStartedTime(long startedTime) { + this.startedTime = startedTime; + } + + public void setFinishedTime(long finishedTime) { + this.finishedTime = finishedTime; + } + + public void setElapsedTime(long elapsedTime) { + this.elapsedTime = elapsedTime; + } + + public void setAmContainerLogs(String amContainerLogs) { + this.amContainerLogs = amContainerLogs; + } + + public void setAmHostHttpAddress(String amHostHttpAddress) { + this.amHostHttpAddress = amHostHttpAddress; + } + + public void setAllocatedMB(int allocatedMB) { + this.allocatedMB = allocatedMB; + } + + public void setAllocatedVCores(int allocatedVCores) { + this.allocatedVCores = allocatedVCores; + } + + public void setRunningContainers(int runningContainers) { + this.runningContainers = runningContainers; + } } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppState.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppState.java new file mode 100644 index 0000000..b987738 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/AppState.java @@ -0,0 +1,46 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "appstate") +@XmlAccessorType(XmlAccessType.FIELD) +public class AppState { + + String state; + + public AppState() { + } + + public AppState(String state) { + this.state = state; + } + + public void setState(String state) { + this.state = state; + } + + public String getState() { + return this.state; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMCustomAuthFilter.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMCustomAuthFilter.java new file mode 100644 index 0000000..d0a0404 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMCustomAuthFilter.java @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp; + +import java.util.Enumeration; +import java.util.Properties; + +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; + +import org.apache.hadoop.security.authentication.server.AuthenticationFilter; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; + +import com.google.inject.Singleton; + +/* + * Helper class to allow testing of RM web services which require authorization + * Add this class as a filter in the Guice injector for the MockRM + * + */ + +@Singleton +public class TestRMCustomAuthFilter extends AuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, FilterConfig filterConfig) throws ServletException { + Properties props = new Properties(); + Enumeration names = filterConfig.getInitParameterNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + if (name.startsWith(configPrefix)) { + String value = filterConfig.getInitParameter(name); + props.put(name.substring(configPrefix.length()), value); + } + } + props.put(AuthenticationFilter.AUTH_TYPE, "simple"); + props.put(PseudoAuthenticationHandler.ANONYMOUS_ALLOWED, "false"); + return props; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesApps.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesApps.java index 45b3803..7697b32 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesApps.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesApps.java @@ -22,12 +22,17 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.IOException; import java.io.StringReader; +import java.io.StringWriter; +import java.util.Arrays; import java.util.Collection; +import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.security.UserGroupInformation; @@ -47,58 +52,50 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler; import org.apache.hadoop.yarn.server.resourcemanager.security.QueueACLsManager; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.AppState; import org.apache.hadoop.yarn.server.security.ApplicationACLsManager; import org.apache.hadoop.yarn.webapp.GenericExceptionHandler; import org.apache.hadoop.yarn.webapp.WebServicesTestUtils; import org.codehaus.jettison.json.JSONArray; import org.codehaus.jettison.json.JSONException; import org.codehaus.jettison.json.JSONObject; +import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.servlet.GuiceServletContextListener; import com.google.inject.servlet.ServletModule; +import com.sun.jersey.api.client.Client; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.api.client.ClientResponse.Status; import com.sun.jersey.api.client.UniformInterfaceException; import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.json.JSONJAXBContext; +import com.sun.jersey.api.json.JSONMarshaller; import com.sun.jersey.core.util.MultivaluedMapImpl; import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; import com.sun.jersey.test.framework.JerseyTest; import com.sun.jersey.test.framework.WebAppDescriptor; +@RunWith(Parameterized.class) public class TestRMWebServicesApps extends JerseyTest { private static MockRM rm; - + private static final int CONTAINER_MB = 1024; - private Injector injector = Guice.createInjector(new ServletModule() { - @Override - protected void configureServlets() { - bind(JAXBContextResolver.class); - bind(RMWebServices.class); - bind(GenericExceptionHandler.class); - Configuration conf = new Configuration(); - conf.setInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, - YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); - conf.setClass(YarnConfiguration.RM_SCHEDULER, FifoScheduler.class, - ResourceScheduler.class); - rm = new MockRM(conf); - bind(ResourceManager.class).toInstance(rm); - bind(RMContext.class).toInstance(rm.getRMContext()); - bind(ApplicationACLsManager.class).toInstance( - rm.getApplicationACLsManager()); - bind(QueueACLsManager.class).toInstance(rm.getQueueACLsManager()); - serve("/*").with(GuiceContainer.class); - } - }); + private Injector injector; + private String webserviceUserName = "testuser"; public class GuiceServletConfig extends GuiceServletContextListener { @@ -108,18 +105,83 @@ protected Injector getInjector() { } } + private Injector getNoAuthInjector() { + return Guice.createInjector(new ServletModule() { + @Override + protected void configureServlets() { + bind(JAXBContextResolver.class); + bind(RMWebServices.class); + bind(GenericExceptionHandler.class); + Configuration conf = new Configuration(); + conf.setInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, + YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); + conf.setClass(YarnConfiguration.RM_SCHEDULER, FifoScheduler.class, + ResourceScheduler.class); + rm = new MockRM(conf); + bind(ResourceManager.class).toInstance(rm); + bind(RMContext.class).toInstance(rm.getRMContext()); + bind(ApplicationACLsManager.class).toInstance( + rm.getApplicationACLsManager()); + bind(QueueACLsManager.class).toInstance(rm.getQueueACLsManager()); + serve("/*").with(GuiceContainer.class); + } + }); + } + + private Injector getSimpleAuthInjector() { + return Guice.createInjector(new ServletModule() { + @Override + protected void configureServlets() { + bind(JAXBContextResolver.class); + bind(RMWebServices.class); + bind(GenericExceptionHandler.class); + Configuration conf = new Configuration(); + conf.setInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, + YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); + conf.setClass(YarnConfiguration.RM_SCHEDULER, FifoScheduler.class, + ResourceScheduler.class); + conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); + // set the admin acls otherwise all users are considered admins + // and we can't test authorization + conf.setStrings(YarnConfiguration.YARN_ADMIN_ACL, "testuser1"); + rm = new MockRM(conf); + bind(ResourceManager.class).toInstance(rm); + bind(RMContext.class).toInstance(rm.getRMContext()); + bind(ApplicationACLsManager.class).toInstance( + rm.getApplicationACLsManager()); + bind(QueueACLsManager.class).toInstance(rm.getQueueACLsManager()); + filter("/*").through(TestRMCustomAuthFilter.class); + serve("/*").with(GuiceContainer.class); + } + }); + } + + @Parameters + public static Collection guiceConfigs() { + return Arrays.asList(new Object[][] { { 0 }, { 1 } }); + } + @Before @Override public void setUp() throws Exception { super.setUp(); } - public TestRMWebServicesApps() { + public TestRMWebServicesApps(int run) { super(new WebAppDescriptor.Builder( - "org.apache.hadoop.yarn.server.resourcemanager.webapp") - .contextListenerClass(GuiceServletConfig.class) - .filterClass(com.google.inject.servlet.GuiceFilter.class) - .contextPath("jersey-guice-filter").servletPath("/").build()); + "org.apache.hadoop.yarn.server.resourcemanager.webapp") + .contextListenerClass(GuiceServletConfig.class) + .filterClass(com.google.inject.servlet.GuiceFilter.class) + .contextPath("jersey-guice-filter").servletPath("/").build()); + switch (run) { + case 0: + default: + injector = getNoAuthInjector(); + break; + case 1: + injector = getSimpleAuthInjector(); + break; + } } @Test @@ -158,10 +220,11 @@ public void testAppsXML() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); RMApp app1 = rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").accept(MediaType.APPLICATION_XML) - .get(ClientResponse.class); + + ClientResponse response = + this.constructWebResource("apps").accept(MediaType.APPLICATION_XML) + .get(ClientResponse.class); + assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType()); String xml = response.getEntity(String.class); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -185,11 +248,9 @@ public void testAppsXMLMulti() throws JSONException, Exception { rm.submitApp(2048, "testwordcount2", "user1"); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").accept(MediaType.APPLICATION_XML) - .get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps").accept(MediaType.APPLICATION_XML) + .get(ClientResponse.class); assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType()); String xml = response.getEntity(String.class); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); @@ -206,10 +267,9 @@ public void testAppsXMLMulti() throws JSONException, Exception { public void testAppsHelper(String path, RMApp app, String media) throws JSONException, Exception { - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path(path).accept(media).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource(path).accept(media).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -227,12 +287,11 @@ public void testAppsQueryState() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps") - .queryParam("state", YarnApplicationState.ACCEPTED.toString()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("state", YarnApplicationState.ACCEPTED.toString()) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -254,12 +313,11 @@ public void testAppsQueryStates() throws JSONException, Exception { amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); MultivaluedMapImpl params = new MultivaluedMapImpl(); params.add("states", YarnApplicationState.ACCEPTED.toString()); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParams(params) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps").queryParams(params) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -268,15 +326,14 @@ public void testAppsQueryStates() throws JSONException, Exception { JSONArray array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 1, array.length()); assertEquals("state not equal to ACCEPTED", "ACCEPTED", array - .getJSONObject(0).getString("state")); + .getJSONObject(0).getString("state")); - r = resource(); params = new MultivaluedMapImpl(); params.add("states", YarnApplicationState.ACCEPTED.toString()); params.add("states", YarnApplicationState.KILLED.toString()); - response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParams(params) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this.constructWebResource("apps").queryParams(params) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -284,11 +341,11 @@ public void testAppsQueryStates() throws JSONException, Exception { assertEquals("incorrect number of elements", 1, apps.length()); array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 2, array.length()); - assertTrue("both app states of ACCEPTED and KILLED are not present", - (array.getJSONObject(0).getString("state").equals("ACCEPTED") && - array.getJSONObject(1).getString("state").equals("KILLED")) || - (array.getJSONObject(0).getString("state").equals("KILLED") && - array.getJSONObject(1).getString("state").equals("ACCEPTED"))); + assertTrue("both app states of ACCEPTED and KILLED are not present", (array + .getJSONObject(0).getString("state").equals("ACCEPTED") && array + .getJSONObject(1).getString("state").equals("KILLED")) + || (array.getJSONObject(0).getString("state").equals("KILLED") && array + .getJSONObject(1).getString("state").equals("ACCEPTED"))); rm.stop(); } @@ -303,12 +360,11 @@ public void testAppsQueryStatesComma() throws JSONException, Exception { amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); MultivaluedMapImpl params = new MultivaluedMapImpl(); params.add("states", YarnApplicationState.ACCEPTED.toString()); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParams(params) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps").queryParams(params) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -317,15 +373,14 @@ public void testAppsQueryStatesComma() throws JSONException, Exception { JSONArray array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 1, array.length()); assertEquals("state not equal to ACCEPTED", "ACCEPTED", array - .getJSONObject(0).getString("state")); + .getJSONObject(0).getString("state")); - r = resource(); params = new MultivaluedMapImpl(); params.add("states", YarnApplicationState.ACCEPTED.toString() + "," + YarnApplicationState.KILLED.toString()); - response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParams(params) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this.constructWebResource("apps").queryParams(params) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -333,12 +388,12 @@ public void testAppsQueryStatesComma() throws JSONException, Exception { assertEquals("incorrect number of elements", 1, apps.length()); array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 2, array.length()); - assertTrue("both app states of ACCEPTED and KILLED are not present", - (array.getJSONObject(0).getString("state").equals("ACCEPTED") && - array.getJSONObject(1).getString("state").equals("KILLED")) || - (array.getJSONObject(0).getString("state").equals("KILLED") && - array.getJSONObject(1).getString("state").equals("ACCEPTED"))); - + assertTrue("both app states of ACCEPTED and KILLED are not present", (array + .getJSONObject(0).getString("state").equals("ACCEPTED") && array + .getJSONObject(1).getString("state").equals("KILLED")) + || (array.getJSONObject(0).getString("state").equals("KILLED") && array + .getJSONObject(1).getString("state").equals("ACCEPTED"))); + rm.stop(); } @@ -348,12 +403,10 @@ public void testAppsQueryStatesNone() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps") - .queryParam("states", YarnApplicationState.RUNNING.toString()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("states", YarnApplicationState.RUNNING.toString()) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -367,12 +420,12 @@ public void testAppsQueryStateNone() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps") - .queryParam("state", YarnApplicationState.RUNNING.toString()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("state", YarnApplicationState.RUNNING.toString()) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -386,12 +439,10 @@ public void testAppsQueryStatesInvalid() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("states", "INVALID_test") - .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); + this.constructWebResource("apps").queryParam("states", "INVALID_test") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid state query"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -403,14 +454,12 @@ public void testAppsQueryStatesInvalid() throws JSONException, Exception { String message = exception.getString("message"); String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); - WebServicesTestUtils.checkStringContains( - "exception message", - "Invalid application-state INVALID_test", - message); + WebServicesTestUtils.checkStringContains("exception message", + "Invalid application-state INVALID_test", message); WebServicesTestUtils.checkStringMatch("exception type", - "BadRequestException", type); + "BadRequestException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "org.apache.hadoop.yarn.webapp.BadRequestException", classname); + "org.apache.hadoop.yarn.webapp.BadRequestException", classname); } finally { rm.stop(); @@ -423,12 +472,10 @@ public void testAppsQueryStateInvalid() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("state", "INVALID_test") - .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); + this.constructWebResource("apps").queryParam("state", "INVALID_test") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid state query"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -440,14 +487,12 @@ public void testAppsQueryStateInvalid() throws JSONException, Exception { String message = exception.getString("message"); String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); - WebServicesTestUtils.checkStringContains( - "exception message", - "Invalid application-state INVALID_test", - message); + WebServicesTestUtils.checkStringContains("exception message", + "Invalid application-state INVALID_test", message); WebServicesTestUtils.checkStringMatch("exception type", - "BadRequestException", type); + "BadRequestException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "org.apache.hadoop.yarn.webapp.BadRequestException", classname); + "org.apache.hadoop.yarn.webapp.BadRequestException", classname); } finally { rm.stop(); @@ -460,11 +505,12 @@ public void testAppsQueryFinalStatus() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("finalStatus", FinalApplicationStatus.UNDEFINED.toString()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this + .constructWebResource("apps") + .queryParam("finalStatus", + FinalApplicationStatus.UNDEFINED.toString()) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -483,11 +529,10 @@ public void testAppsQueryFinalStatusNone() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("finalStatus", FinalApplicationStatus.KILLED.toString()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("finalStatus", FinalApplicationStatus.KILLED.toString()) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -501,12 +546,11 @@ public void testAppsQueryFinalStatusInvalid() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("finalStatus", "INVALID_test") - .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); + this.constructWebResource("apps") + .queryParam("finalStatus", "INVALID_test") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid state query"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -519,14 +563,14 @@ public void testAppsQueryFinalStatusInvalid() throws JSONException, Exception { String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); WebServicesTestUtils - .checkStringContains( - "exception message", - "org.apache.hadoop.yarn.api.records.FinalApplicationStatus.INVALID_test", - message); + .checkStringContains( + "exception message", + "org.apache.hadoop.yarn.api.records.FinalApplicationStatus.INVALID_test", + message); WebServicesTestUtils.checkStringMatch("exception type", - "IllegalArgumentException", type); + "IllegalArgumentException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "java.lang.IllegalArgumentException", classname); + "java.lang.IllegalArgumentException", classname); } finally { rm.stop(); @@ -541,15 +585,13 @@ public void testAppsQueryUser() throws JSONException, Exception { rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - ClientResponse response = r - .path("ws") - .path("v1") - .path("cluster") - .path("apps") - .queryParam("user", + + ClientResponse response = + this + .constructWebResource("apps") + .queryParam("user", UserGroupInformation.getCurrentUser().getShortUserName()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); @@ -569,11 +611,9 @@ public void testAppsQueryQueue() throws JSONException, Exception { rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("queue", "default") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps").queryParam("queue", "default") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -591,10 +631,9 @@ public void testAppsQueryLimit() throws JSONException, Exception { rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("limit", "2") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps").queryParam("limit", "2") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -614,10 +653,10 @@ public void testAppsQueryStartBegin() throws JSONException, Exception { rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("startedTimeBegin", String.valueOf(start)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("startedTimeBegin", String.valueOf(start)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -637,10 +676,10 @@ public void testAppsQueryStartBeginSome() throws JSONException, Exception { long start = System.currentTimeMillis(); Thread.sleep(1); rm.submitApp(CONTAINER_MB); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("startedTimeBegin", String.valueOf(start)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("startedTimeBegin", String.valueOf(start)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -660,10 +699,10 @@ public void testAppsQueryStartEnd() throws JSONException, Exception { rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("startedTimeEnd", String.valueOf(end)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("startedTimeEnd", String.valueOf(end)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -682,11 +721,11 @@ public void testAppsQueryStartBeginEnd() throws JSONException, Exception { long end = System.currentTimeMillis(); Thread.sleep(1); rm.submitApp(CONTAINER_MB); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("startedTimeBegin", String.valueOf(start)) - .queryParam("startedTimeEnd", String.valueOf(end)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("startedTimeBegin", String.valueOf(start)) + .queryParam("startedTimeEnd", String.valueOf(end)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -706,19 +745,18 @@ public void testAppsQueryFinishBegin() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); // finish App - MockAM am = rm - .sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); + MockAM am = + rm.sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); am.registerAppAttempt(); am.unregisterAppAttempt(); amNodeManager.nodeHeartbeat(app1.getCurrentAppAttempt().getAppAttemptId(), - 1, ContainerState.COMPLETE); + 1, ContainerState.COMPLETE); rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); - - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("finishedTimeBegin", String.valueOf(start)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("finishedTimeBegin", String.valueOf(start)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -736,21 +774,21 @@ public void testAppsQueryFinishEnd() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); // finish App - MockAM am = rm - .sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); + MockAM am = + rm.sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); am.registerAppAttempt(); am.unregisterAppAttempt(); amNodeManager.nodeHeartbeat(app1.getCurrentAppAttempt().getAppAttemptId(), - 1, ContainerState.COMPLETE); + 1, ContainerState.COMPLETE); rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); long end = System.currentTimeMillis(); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("finishedTimeEnd", String.valueOf(end)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("finishedTimeEnd", String.valueOf(end)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -770,22 +808,22 @@ public void testAppsQueryFinishBeginEnd() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); // finish App - MockAM am = rm - .sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); + MockAM am = + rm.sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); am.registerAppAttempt(); am.unregisterAppAttempt(); amNodeManager.nodeHeartbeat(app1.getCurrentAppAttempt().getAppAttemptId(), - 1, ContainerState.COMPLETE); + 1, ContainerState.COMPLETE); rm.submitApp(CONTAINER_MB); rm.submitApp(CONTAINER_MB); long end = System.currentTimeMillis(); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("finishedTimeBegin", String.valueOf(start)) - .queryParam("finishedTimeEnd", String.valueOf(end)) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("finishedTimeBegin", String.valueOf(start)) + .queryParam("finishedTimeEnd", String.valueOf(end)) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -804,22 +842,22 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); // finish App - MockAM am = rm - .sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); + MockAM am = + rm.sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); am.registerAppAttempt(); am.unregisterAppAttempt(); amNodeManager.nodeHeartbeat(app1.getCurrentAppAttempt().getAppAttemptId(), - 1, ContainerState.COMPLETE); + 1, ContainerState.COMPLETE); rm.submitApp(CONTAINER_MB, "", UserGroupInformation.getCurrentUser() - .getShortUserName(), null, false, null, 2, null, "MAPREDUCE"); + .getShortUserName(), null, false, null, 2, null, "MAPREDUCE"); rm.submitApp(CONTAINER_MB, "", UserGroupInformation.getCurrentUser() - .getShortUserName(), null, false, null, 2, null, "NON-YARN"); + .getShortUserName(), null, false, null, 2, null, "NON-YARN"); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("applicationTypes", "MAPREDUCE") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps") + .queryParam("applicationTypes", "MAPREDUCE") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -828,14 +866,13 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { JSONArray array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 1, array.length()); assertEquals("MAPREDUCE", - array.getJSONObject(0).getString("applicationType")); + array.getJSONObject(0).getString("applicationType")); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", "YARN") - .queryParam("applicationTypes", "MAPREDUCE") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", "YARN") + .queryParam("applicationTypes", "MAPREDUCE") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -844,17 +881,15 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 2, array.length()); assertTrue((array.getJSONObject(0).getString("applicationType") - .equals("YARN") && array.getJSONObject(1).getString("applicationType") - .equals("MAPREDUCE")) || - (array.getJSONObject(1).getString("applicationType").equals("YARN") - && array.getJSONObject(0).getString("applicationType") - .equals("MAPREDUCE"))); + .equals("YARN") && array.getJSONObject(1).getString("applicationType") + .equals("MAPREDUCE")) + || (array.getJSONObject(1).getString("applicationType").equals("YARN") && array + .getJSONObject(0).getString("applicationType").equals("MAPREDUCE"))); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", "YARN,NON-YARN") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", "YARN,NON-YARN") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -863,16 +898,14 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 2, array.length()); assertTrue((array.getJSONObject(0).getString("applicationType") - .equals("YARN") && array.getJSONObject(1).getString("applicationType") - .equals("NON-YARN")) || - (array.getJSONObject(1).getString("applicationType").equals("YARN") - && array.getJSONObject(0).getString("applicationType") - .equals("NON-YARN"))); - - r = resource(); - response = r.path("ws").path("v1").path("cluster") - .path("apps").queryParam("applicationTypes", "") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + .equals("YARN") && array.getJSONObject(1).getString("applicationType") + .equals("NON-YARN")) + || (array.getJSONObject(1).getString("applicationType").equals("YARN") && array + .getJSONObject(0).getString("applicationType").equals("NON-YARN"))); + + response = + this.constructWebResource("apps").queryParam("applicationTypes", "") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -881,12 +914,11 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 3, array.length()); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", "YARN,NON-YARN") - .queryParam("applicationTypes", "MAPREDUCE") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", "YARN,NON-YARN") + .queryParam("applicationTypes", "MAPREDUCE") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -895,12 +927,11 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 3, array.length()); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", "YARN") - .queryParam("applicationTypes", "") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", "YARN") + .queryParam("applicationTypes", "") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -908,14 +939,12 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { assertEquals("incorrect number of elements", 1, apps.length()); array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 1, array.length()); - assertEquals("YARN", - array.getJSONObject(0).getString("applicationType")); + assertEquals("YARN", array.getJSONObject(0).getString("applicationType")); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", ",,, ,, YARN ,, ,") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", ",,, ,, YARN ,, ,") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -923,14 +952,12 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { assertEquals("incorrect number of elements", 1, apps.length()); array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 1, array.length()); - assertEquals("YARN", - array.getJSONObject(0).getString("applicationType")); + assertEquals("YARN", array.getJSONObject(0).getString("applicationType")); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", ",,, ,, ,, ,") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", ",,, ,, ,, ,") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -939,11 +966,10 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 3, array.length()); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", "YARN, ,NON-YARN, ,,") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", "YARN, ,NON-YARN, ,,") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -952,18 +978,16 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 2, array.length()); assertTrue((array.getJSONObject(0).getString("applicationType") - .equals("YARN") && array.getJSONObject(1).getString("applicationType") - .equals("NON-YARN")) || - (array.getJSONObject(1).getString("applicationType").equals("YARN") - && array.getJSONObject(0).getString("applicationType") - .equals("NON-YARN"))); + .equals("YARN") && array.getJSONObject(1).getString("applicationType") + .equals("NON-YARN")) + || (array.getJSONObject(1).getString("applicationType").equals("YARN") && array + .getJSONObject(0).getString("applicationType").equals("NON-YARN"))); - r = resource(); response = - r.path("ws").path("v1").path("cluster").path("apps") - .queryParam("applicationTypes", " YARN, , ,,,") - .queryParam("applicationTypes", "MAPREDUCE , ,, ,") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + this.constructWebResource("apps") + .queryParam("applicationTypes", " YARN, , ,,,") + .queryParam("applicationTypes", "MAPREDUCE , ,, ,") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -972,11 +996,10 @@ public void testAppsQueryAppTypes() throws JSONException, Exception { array = apps.getJSONArray("app"); assertEquals("incorrect number of elements", 2, array.length()); assertTrue((array.getJSONObject(0).getString("applicationType") - .equals("YARN") && array.getJSONObject(1).getString("applicationType") - .equals("MAPREDUCE")) || - (array.getJSONObject(1).getString("applicationType").equals("YARN") - && array.getJSONObject(0).getString("applicationType") - .equals("MAPREDUCE"))); + .equals("YARN") && array.getJSONObject(1).getString("applicationType") + .equals("MAPREDUCE")) + || (array.getJSONObject(1).getString("applicationType").equals("YARN") && array + .getJSONObject(0).getString("applicationType").equals("MAPREDUCE"))); rm.stop(); } @@ -987,27 +1010,28 @@ public void testAppStatistics() throws JSONException, Exception { rm.start(); MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 4096); Thread.sleep(1); - RMApp app1 = rm.submitApp(CONTAINER_MB, "", UserGroupInformation.getCurrentUser() - .getShortUserName(), null, false, null, 2, null, "MAPREDUCE"); + RMApp app1 = + rm.submitApp(CONTAINER_MB, "", UserGroupInformation.getCurrentUser() + .getShortUserName(), null, false, null, 2, null, "MAPREDUCE"); amNodeManager.nodeHeartbeat(true); // finish App - MockAM am = rm - .sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); + MockAM am = + rm.sendAMLaunched(app1.getCurrentAppAttempt().getAppAttemptId()); am.registerAppAttempt(); am.unregisterAppAttempt(); - amNodeManager.nodeHeartbeat(app1.getCurrentAppAttempt().getAppAttemptId(), - 1, ContainerState.COMPLETE); + amNodeManager.nodeHeartbeat( + app1.getCurrentAppAttempt().getAppAttemptId(), 1, + ContainerState.COMPLETE); rm.submitApp(CONTAINER_MB, "", UserGroupInformation.getCurrentUser() - .getShortUserName(), null, false, null, 2, null, "MAPREDUCE"); + .getShortUserName(), null, false, null, 2, null, "MAPREDUCE"); rm.submitApp(CONTAINER_MB, "", UserGroupInformation.getCurrentUser() - .getShortUserName(), null, false, null, 2, null, "OTHER"); + .getShortUserName(), null, false, null, 2, null, "OTHER"); // zero type, zero state - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("appstatistics") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("appstatistics") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -1015,13 +1039,13 @@ public void testAppStatistics() throws JSONException, Exception { assertEquals("incorrect number of elements", 1, appsStatInfo.length()); JSONArray statItems = appsStatInfo.getJSONArray("statItem"); assertEquals("incorrect number of elements", - YarnApplicationState.values().length, statItems.length()); + YarnApplicationState.values().length, statItems.length()); for (int i = 0; i < YarnApplicationState.values().length; ++i) { assertEquals("*", statItems.getJSONObject(0).getString("type")); if (statItems.getJSONObject(0).getString("state").equals("ACCEPTED")) { assertEquals("2", statItems.getJSONObject(0).getString("count")); - } else if ( - statItems.getJSONObject(0).getString("state").equals("FINISHED")) { + } else if (statItems.getJSONObject(0).getString("state") + .equals("FINISHED")) { assertEquals("1", statItems.getJSONObject(0).getString("count")); } else { assertEquals("0", statItems.getJSONObject(0).getString("count")); @@ -1029,11 +1053,10 @@ public void testAppStatistics() throws JSONException, Exception { } // zero type, one state - r = resource(); - response = r.path("ws").path("v1").path("cluster") - .path("appstatistics") - .queryParam("states", YarnApplicationState.ACCEPTED.toString()) - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this.constructWebResource("appstatistics") + .queryParam("states", YarnApplicationState.ACCEPTED.toString()) + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -1046,11 +1069,10 @@ public void testAppStatistics() throws JSONException, Exception { assertEquals("2", statItems.getJSONObject(0).getString("count")); // one type, zero state - r = resource(); - response = r.path("ws").path("v1").path("cluster") - .path("appstatistics") - .queryParam("applicationTypes", "MAPREDUCE") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this.constructWebResource("appstatistics") + .queryParam("applicationTypes", "MAPREDUCE") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -1058,13 +1080,13 @@ public void testAppStatistics() throws JSONException, Exception { assertEquals("incorrect number of elements", 1, appsStatInfo.length()); statItems = appsStatInfo.getJSONArray("statItem"); assertEquals("incorrect number of elements", - YarnApplicationState.values().length, statItems.length()); + YarnApplicationState.values().length, statItems.length()); for (int i = 0; i < YarnApplicationState.values().length; ++i) { assertEquals("mapreduce", statItems.getJSONObject(0).getString("type")); if (statItems.getJSONObject(0).getString("state").equals("ACCEPTED")) { assertEquals("1", statItems.getJSONObject(0).getString("count")); - } else if ( - statItems.getJSONObject(0).getString("state").equals("FINISHED")) { + } else if (statItems.getJSONObject(0).getString("state") + .equals("FINISHED")) { assertEquals("1", statItems.getJSONObject(0).getString("count")); } else { assertEquals("0", statItems.getJSONObject(0).getString("count")); @@ -1072,11 +1094,10 @@ public void testAppStatistics() throws JSONException, Exception { } // two types, zero state - r = resource(); - response = r.path("ws").path("v1").path("cluster") - .path("appstatistics") - .queryParam("applicationTypes", "MAPREDUCE,OTHER") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this.constructWebResource("appstatistics") + .queryParam("applicationTypes", "MAPREDUCE,OTHER") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus()); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); @@ -1087,20 +1108,22 @@ public void testAppStatistics() throws JSONException, Exception { String type = exception.getString("exception"); String className = exception.getString("javaClassName"); WebServicesTestUtils.checkStringContains("exception message", - "we temporarily support at most one applicationType", message); + "we temporarily support at most one applicationType", message); WebServicesTestUtils.checkStringEqual("exception type", - "BadRequestException", type); + "BadRequestException", type); WebServicesTestUtils.checkStringEqual("exception className", - "org.apache.hadoop.yarn.webapp.BadRequestException", className); + "org.apache.hadoop.yarn.webapp.BadRequestException", className); // one type, two states - r = resource(); - response = r.path("ws").path("v1").path("cluster") - .path("appstatistics") - .queryParam("states", YarnApplicationState.FINISHED.toString() - + "," + YarnApplicationState.ACCEPTED.toString()) - .queryParam("applicationTypes", "MAPREDUCE") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this + .constructWebResource("appstatistics") + .queryParam( + "states", + YarnApplicationState.FINISHED.toString() + "," + + YarnApplicationState.ACCEPTED.toString()) + .queryParam("applicationTypes", "MAPREDUCE") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -1110,20 +1133,20 @@ public void testAppStatistics() throws JSONException, Exception { assertEquals("incorrect number of elements", 2, statItems.length()); JSONObject statItem1 = statItems.getJSONObject(0); JSONObject statItem2 = statItems.getJSONObject(1); - assertTrue((statItem1.getString("state").equals("ACCEPTED") && - statItem2.getString("state").equals("FINISHED")) || - (statItem2.getString("state").equals("ACCEPTED") && - statItem1.getString("state").equals("FINISHED"))); + assertTrue((statItem1.getString("state").equals("ACCEPTED") && statItem2 + .getString("state").equals("FINISHED")) + || (statItem2.getString("state").equals("ACCEPTED") && statItem1 + .getString("state").equals("FINISHED"))); assertEquals("mapreduce", statItem1.getString("type")); assertEquals("1", statItem1.getString("count")); assertEquals("mapreduce", statItem2.getString("type")); assertEquals("1", statItem2.getString("count")); // invalid state - r = resource(); - response = r.path("ws").path("v1").path("cluster") - .path("appstatistics").queryParam("states", "wrong_state") - .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); + response = + this.constructWebResource("appstatistics") + .queryParam("states", "wrong_state") + .accept(MediaType.APPLICATION_JSON).get(ClientResponse.class); assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus()); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); json = response.getEntity(JSONObject.class); @@ -1134,11 +1157,11 @@ public void testAppStatistics() throws JSONException, Exception { type = exception.getString("exception"); className = exception.getString("javaClassName"); WebServicesTestUtils.checkStringContains("exception message", - "Invalid application-state wrong_state", message); + "Invalid application-state wrong_state", message); WebServicesTestUtils.checkStringEqual("exception type", - "BadRequestException", type); + "BadRequestException", type); WebServicesTestUtils.checkStringEqual("exception className", - "org.apache.hadoop.yarn.webapp.BadRequestException", className); + "org.apache.hadoop.yarn.webapp.BadRequestException", className); } finally { rm.stop(); } @@ -1151,7 +1174,7 @@ public void testSingleApp() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); amNodeManager.nodeHeartbeat(true); testSingleAppsHelper(app1.getApplicationId().toString(), app1, - MediaType.APPLICATION_JSON); + MediaType.APPLICATION_JSON); rm.stop(); } @@ -1162,7 +1185,7 @@ public void testSingleAppsSlash() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); testSingleAppsHelper(app1.getApplicationId().toString() + "/", app1, - MediaType.APPLICATION_JSON); + MediaType.APPLICATION_JSON); rm.stop(); } @@ -1182,12 +1205,10 @@ public void testInvalidApp() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .path("application_invalid_12").accept(MediaType.APPLICATION_JSON) - .get(JSONObject.class); + this.constructWebResource("apps", "application_invalid_12") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid appid"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -1201,11 +1222,11 @@ public void testInvalidApp() throws JSONException, Exception { String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); WebServicesTestUtils.checkStringMatch("exception message", - "For input string: \"invalid\"", message); + "For input string: \"invalid\"", message); WebServicesTestUtils.checkStringMatch("exception type", - "NumberFormatException", type); + "NumberFormatException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "java.lang.NumberFormatException", classname); + "java.lang.NumberFormatException", classname); } finally { rm.stop(); @@ -1218,12 +1239,10 @@ public void testNonexistApp() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .path("application_00000_0099").accept(MediaType.APPLICATION_JSON) - .get(JSONObject.class); + this.constructWebResource("apps", "application_00000_0099") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid appid"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -1238,12 +1257,12 @@ public void testNonexistApp() throws JSONException, Exception { String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); WebServicesTestUtils.checkStringMatch("exception message", - "java.lang.Exception: app with id: application_00000_0099 not found", - message); + "java.lang.Exception: app with id: application_00000_0099 not found", + message); WebServicesTestUtils.checkStringMatch("exception type", - "NotFoundException", type); + "NotFoundException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "org.apache.hadoop.yarn.webapp.NotFoundException", classname); + "org.apache.hadoop.yarn.webapp.NotFoundException", classname); } finally { rm.stop(); } @@ -1251,9 +1270,9 @@ public void testNonexistApp() throws JSONException, Exception { public void testSingleAppsHelper(String path, RMApp app, String media) throws JSONException, Exception { - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").path(path).accept(media).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps", path).accept(media) + .get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); @@ -1267,10 +1286,9 @@ public void testSingleAppsXML() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); RMApp app1 = rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").path(app1.getApplicationId().toString()) - .accept(MediaType.APPLICATION_XML).get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps", app1.getApplicationId().toString()) + .accept(MediaType.APPLICATION_XML).get(ClientResponse.class); assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType()); String xml = response.getEntity(String.class); @@ -1288,29 +1306,29 @@ public void testSingleAppsXML() throws JSONException, Exception { public void verifyAppsXML(NodeList nodes, RMApp app) throws JSONException, Exception { - for (int i = 0; i < nodes.getLength(); i++) { + for (int i = 0; i < nodes.getLength(); i++) { Element element = (Element) nodes.item(i); verifyAppInfoGeneric(app, - WebServicesTestUtils.getXmlString(element, "id"), - WebServicesTestUtils.getXmlString(element, "user"), - WebServicesTestUtils.getXmlString(element, "name"), - WebServicesTestUtils.getXmlString(element, "applicationType"), - WebServicesTestUtils.getXmlString(element, "queue"), - WebServicesTestUtils.getXmlString(element, "state"), - WebServicesTestUtils.getXmlString(element, "finalStatus"), - WebServicesTestUtils.getXmlFloat(element, "progress"), - WebServicesTestUtils.getXmlString(element, "trackingUI"), - WebServicesTestUtils.getXmlString(element, "diagnostics"), - WebServicesTestUtils.getXmlLong(element, "clusterId"), - WebServicesTestUtils.getXmlLong(element, "startedTime"), - WebServicesTestUtils.getXmlLong(element, "finishedTime"), - WebServicesTestUtils.getXmlLong(element, "elapsedTime"), - WebServicesTestUtils.getXmlString(element, "amHostHttpAddress"), - WebServicesTestUtils.getXmlString(element, "amContainerLogs"), - WebServicesTestUtils.getXmlInt(element, "allocatedMB"), - WebServicesTestUtils.getXmlInt(element, "allocatedVCores"), - WebServicesTestUtils.getXmlInt(element, "runningContainers")); + WebServicesTestUtils.getXmlString(element, "id"), + WebServicesTestUtils.getXmlString(element, "user"), + WebServicesTestUtils.getXmlString(element, "name"), + WebServicesTestUtils.getXmlString(element, "applicationType"), + WebServicesTestUtils.getXmlString(element, "queue"), + WebServicesTestUtils.getXmlString(element, "state"), + WebServicesTestUtils.getXmlString(element, "finalStatus"), + WebServicesTestUtils.getXmlFloat(element, "progress"), + WebServicesTestUtils.getXmlString(element, "trackingUI"), + WebServicesTestUtils.getXmlString(element, "diagnostics"), + WebServicesTestUtils.getXmlLong(element, "clusterId"), + WebServicesTestUtils.getXmlLong(element, "startedTime"), + WebServicesTestUtils.getXmlLong(element, "finishedTime"), + WebServicesTestUtils.getXmlLong(element, "elapsedTime"), + WebServicesTestUtils.getXmlString(element, "amHostHttpAddress"), + WebServicesTestUtils.getXmlString(element, "amContainerLogs"), + WebServicesTestUtils.getXmlInt(element, "allocatedMB"), + WebServicesTestUtils.getXmlInt(element, "allocatedVCores"), + WebServicesTestUtils.getXmlInt(element, "runningContainers")); } } @@ -1321,53 +1339,54 @@ public void verifyAppInfo(JSONObject info, RMApp app) throws JSONException, assertEquals("incorrect number of elements", 20, info.length()); verifyAppInfoGeneric(app, info.getString("id"), info.getString("user"), - info.getString("name"), info.getString("applicationType"), info.getString("queue"), - info.getString("state"), info.getString("finalStatus"), - (float) info.getDouble("progress"), info.getString("trackingUI"), - info.getString("diagnostics"), info.getLong("clusterId"), - info.getLong("startedTime"), info.getLong("finishedTime"), - info.getLong("elapsedTime"), info.getString("amHostHttpAddress"), - info.getString("amContainerLogs"), info.getInt("allocatedMB"), - info.getInt("allocatedVCores"), info.getInt("runningContainers")); + info.getString("name"), info.getString("applicationType"), + info.getString("queue"), info.getString("state"), + info.getString("finalStatus"), (float) info.getDouble("progress"), + info.getString("trackingUI"), info.getString("diagnostics"), + info.getLong("clusterId"), info.getLong("startedTime"), + info.getLong("finishedTime"), info.getLong("elapsedTime"), + info.getString("amHostHttpAddress"), info.getString("amContainerLogs"), + info.getInt("allocatedMB"), info.getInt("allocatedVCores"), + info.getInt("runningContainers")); } public void verifyAppInfoGeneric(RMApp app, String id, String user, - String name, String applicationType, String queue, String state, String finalStatus, - float progress, String trackingUI, String diagnostics, long clusterId, - long startedTime, long finishedTime, long elapsedTime, - String amHostHttpAddress, String amContainerLogs, int allocatedMB, - int allocatedVCores, int numContainers) throws JSONException, - Exception { + String name, String applicationType, String queue, String state, + String finalStatus, float progress, String trackingUI, + String diagnostics, long clusterId, long startedTime, long finishedTime, + long elapsedTime, String amHostHttpAddress, String amContainerLogs, + int allocatedMB, int allocatedVCores, int numContainers) + throws JSONException, Exception { WebServicesTestUtils.checkStringMatch("id", app.getApplicationId() - .toString(), id); + .toString(), id); WebServicesTestUtils.checkStringMatch("user", app.getUser(), user); WebServicesTestUtils.checkStringMatch("name", app.getName(), name); WebServicesTestUtils.checkStringMatch("applicationType", app.getApplicationType(), applicationType); WebServicesTestUtils.checkStringMatch("queue", app.getQueue(), queue); WebServicesTestUtils.checkStringMatch("state", app.getState().toString(), - state); + state); WebServicesTestUtils.checkStringMatch("finalStatus", app - .getFinalApplicationStatus().toString(), finalStatus); + .getFinalApplicationStatus().toString(), finalStatus); assertEquals("progress doesn't match", 0, progress, 0.0); WebServicesTestUtils.checkStringMatch("trackingUI", "UNASSIGNED", - trackingUI); + trackingUI); WebServicesTestUtils.checkStringMatch("diagnostics", app.getDiagnostics() - .toString(), diagnostics); + .toString(), diagnostics); assertEquals("clusterId doesn't match", - ResourceManager.getClusterTimeStamp(), clusterId); + ResourceManager.getClusterTimeStamp(), clusterId); assertEquals("startedTime doesn't match", app.getStartTime(), startedTime); assertEquals("finishedTime doesn't match", app.getFinishTime(), - finishedTime); + finishedTime); assertTrue("elapsed time not greater than 0", elapsedTime > 0); WebServicesTestUtils.checkStringMatch("amHostHttpAddress", app - .getCurrentAppAttempt().getMasterContainer().getNodeHttpAddress(), - amHostHttpAddress); + .getCurrentAppAttempt().getMasterContainer().getNodeHttpAddress(), + amHostHttpAddress); assertTrue("amContainerLogs doesn't match", - amContainerLogs.startsWith("http://")); + amContainerLogs.startsWith("http://")); assertTrue("amContainerLogs doesn't contain user info", - amContainerLogs.endsWith("/" + app.getUser())); + amContainerLogs.endsWith("/" + app.getUser())); assertEquals("allocatedMB doesn't match", 1024, allocatedMB); assertEquals("allocatedVCores doesn't match", 1, allocatedVCores); assertEquals("numContainers doesn't match", 1, numContainers); @@ -1380,24 +1399,25 @@ public void testAppAttempts() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); amNodeManager.nodeHeartbeat(true); testAppAttemptsHelper(app1.getApplicationId().toString(), app1, - MediaType.APPLICATION_JSON); + MediaType.APPLICATION_JSON); rm.stop(); } - @Test (timeout = 20000) + @Test(timeout = 20000) public void testMultipleAppAttempts() throws JSONException, Exception { rm.start(); MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 8192); RMApp app1 = rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); MockAM am = MockRM.launchAndRegisterAM(app1, rm, amNodeManager); - int maxAppAttempts = rm.getConfig().getInt( - YarnConfiguration.RM_AM_MAX_ATTEMPTS, - YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); + int maxAppAttempts = + rm.getConfig().getInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, + YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); assertTrue(maxAppAttempts > 1); int numAttempt = 1; while (true) { // fail the AM by sending CONTAINER_FINISHED event without registering. - amNodeManager.nodeHeartbeat(am.getApplicationAttemptId(), 1, ContainerState.COMPLETE); + amNodeManager.nodeHeartbeat(am.getApplicationAttemptId(), 1, + ContainerState.COMPLETE); am.waitForState(RMAppAttemptState.FAILED); if (numAttempt == maxAppAttempts) { rm.waitForState(app1.getApplicationId(), RMAppState.FAILED); @@ -1408,10 +1428,10 @@ public void testMultipleAppAttempts() throws JSONException, Exception { am = MockRM.launchAndRegisterAM(app1, rm, amNodeManager); numAttempt++; } - assertEquals("incorrect number of attempts", maxAppAttempts, - app1.getAppAttempts().values().size()); + assertEquals("incorrect number of attempts", maxAppAttempts, app1 + .getAppAttempts().values().size()); testAppAttemptsHelper(app1.getApplicationId().toString(), app1, - MediaType.APPLICATION_JSON); + MediaType.APPLICATION_JSON); rm.stop(); } @@ -1422,7 +1442,7 @@ public void testAppAttemptsSlash() throws JSONException, Exception { RMApp app1 = rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); testAppAttemptsHelper(app1.getApplicationId().toString() + "/", app1, - MediaType.APPLICATION_JSON); + MediaType.APPLICATION_JSON); rm.stop(); } @@ -1442,12 +1462,10 @@ public void testInvalidAppAttempts() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .path("application_invalid_12").accept(MediaType.APPLICATION_JSON) - .get(JSONObject.class); + this.constructWebResource("apps", "application_invalid_12") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid appid"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -1461,11 +1479,11 @@ public void testInvalidAppAttempts() throws JSONException, Exception { String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); WebServicesTestUtils.checkStringMatch("exception message", - "For input string: \"invalid\"", message); + "For input string: \"invalid\"", message); WebServicesTestUtils.checkStringMatch("exception type", - "NumberFormatException", type); + "NumberFormatException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "java.lang.NumberFormatException", classname); + "java.lang.NumberFormatException", classname); } finally { rm.stop(); @@ -1478,12 +1496,10 @@ public void testNonexistAppAttempts() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); rm.submitApp(CONTAINER_MB, "testwordcount", "user1"); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); try { - r.path("ws").path("v1").path("cluster").path("apps") - .path("application_00000_0099").accept(MediaType.APPLICATION_JSON) - .get(JSONObject.class); + this.constructWebResource("apps", "application_00000_0099") + .accept(MediaType.APPLICATION_JSON).get(JSONObject.class); fail("should have thrown exception on invalid appid"); } catch (UniformInterfaceException ue) { ClientResponse response = ue.getResponse(); @@ -1498,12 +1514,12 @@ public void testNonexistAppAttempts() throws JSONException, Exception { String type = exception.getString("exception"); String classname = exception.getString("javaClassName"); WebServicesTestUtils.checkStringMatch("exception message", - "java.lang.Exception: app with id: application_00000_0099 not found", - message); + "java.lang.Exception: app with id: application_00000_0099 not found", + message); WebServicesTestUtils.checkStringMatch("exception type", - "NotFoundException", type); + "NotFoundException", type); WebServicesTestUtils.checkStringMatch("exception classname", - "org.apache.hadoop.yarn.webapp.NotFoundException", classname); + "org.apache.hadoop.yarn.webapp.NotFoundException", classname); } finally { rm.stop(); } @@ -1511,10 +1527,9 @@ public void testNonexistAppAttempts() throws JSONException, Exception { public void testAppAttemptsHelper(String path, RMApp app, String media) throws JSONException, Exception { - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").path(path).path("appattempts").accept(media) - .get(ClientResponse.class); + ClientResponse response = + this.constructWebResource("apps", path, "appattempts").accept(media) + .get(ClientResponse.class); assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); JSONObject json = response.getEntity(JSONObject.class); assertEquals("incorrect number of elements", 1, json.length()); @@ -1524,7 +1539,7 @@ public void testAppAttemptsHelper(String path, RMApp app, String media) Collection attempts = app.getAppAttempts().values(); assertEquals("incorrect number of elements", attempts.size(), - jsonArray.length()); + jsonArray.length()); // Verify these parallel arrays are the same int i = 0; @@ -1541,11 +1556,11 @@ public void testAppAttemptsXML() throws JSONException, Exception { MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); RMApp app1 = rm.submitApp(CONTAINER_MB, "testwordcount", user); amNodeManager.nodeHeartbeat(true); - WebResource r = resource(); - ClientResponse response = r.path("ws").path("v1").path("cluster") - .path("apps").path(app1.getApplicationId().toString()) - .path("appattempts").accept(MediaType.APPLICATION_XML) - .get(ClientResponse.class); + ClientResponse response = + this + .constructWebResource("apps", app1.getApplicationId().toString(), + "appattempts").accept(MediaType.APPLICATION_XML) + .get(ClientResponse.class); assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType()); String xml = response.getEntity(String.class); @@ -1563,54 +1578,346 @@ public void testAppAttemptsXML() throws JSONException, Exception { } public void verifyAppAttemptsXML(NodeList nodes, RMAppAttempt appAttempt, - String user) - throws JSONException, Exception { + String user) throws JSONException, Exception { for (int i = 0; i < nodes.getLength(); i++) { Element element = (Element) nodes.item(i); verifyAppAttemptInfoGeneric(appAttempt, - WebServicesTestUtils.getXmlInt(element, "id"), - WebServicesTestUtils.getXmlLong(element, "startTime"), - WebServicesTestUtils.getXmlString(element, "containerId"), - WebServicesTestUtils.getXmlString(element, "nodeHttpAddress"), - WebServicesTestUtils.getXmlString(element, "nodeId"), - WebServicesTestUtils.getXmlString(element, "logsLink"), user); + WebServicesTestUtils.getXmlInt(element, "id"), + WebServicesTestUtils.getXmlLong(element, "startTime"), + WebServicesTestUtils.getXmlString(element, "containerId"), + WebServicesTestUtils.getXmlString(element, "nodeHttpAddress"), + WebServicesTestUtils.getXmlString(element, "nodeId"), + WebServicesTestUtils.getXmlString(element, "logsLink"), user); } } public void verifyAppAttemptsInfo(JSONObject info, RMAppAttempt appAttempt, - String user) - throws JSONException, Exception { + String user) throws JSONException, Exception { assertEquals("incorrect number of elements", 6, info.length()); verifyAppAttemptInfoGeneric(appAttempt, info.getInt("id"), - info.getLong("startTime"), info.getString("containerId"), - info.getString("nodeHttpAddress"), info.getString("nodeId"), - info.getString("logsLink"), user); + info.getLong("startTime"), info.getString("containerId"), + info.getString("nodeHttpAddress"), info.getString("nodeId"), + info.getString("logsLink"), user); } public void verifyAppAttemptInfoGeneric(RMAppAttempt appAttempt, int id, - long startTime, String containerId, String nodeHttpAddress, String nodeId, - String logsLink, String user) - throws JSONException, Exception { + long startTime, String containerId, String nodeHttpAddress, + String nodeId, String logsLink, String user) throws JSONException, + Exception { assertEquals("id doesn't match", appAttempt.getAppAttemptId() - .getAttemptId(), id); + .getAttemptId(), id); assertEquals("startedTime doesn't match", appAttempt.getStartTime(), - startTime); + startTime); WebServicesTestUtils.checkStringMatch("containerId", appAttempt - .getMasterContainer().getId().toString(), containerId); + .getMasterContainer().getId().toString(), containerId); WebServicesTestUtils.checkStringMatch("nodeHttpAddress", appAttempt - .getMasterContainer().getNodeHttpAddress(), nodeHttpAddress); + .getMasterContainer().getNodeHttpAddress(), nodeHttpAddress); WebServicesTestUtils.checkStringMatch("nodeId", appAttempt - .getMasterContainer().getNodeId().toString(), nodeId); + .getMasterContainer().getNodeId().toString(), nodeId); assertTrue("logsLink doesn't match", logsLink.startsWith("//")); - assertTrue( - "logsLink doesn't contain user info", logsLink.endsWith("/" - + user)); + assertTrue("logsLink doesn't contain user info", + logsLink.endsWith("/" + user)); + } + + private boolean isAuthorizationEnabled() { + return rm.getConfig().getBoolean(YarnConfiguration.YARN_ACL_ENABLE, false); } -} + private WebResource constructWebResource(WebResource r, String... paths) { + WebResource rt = r; + for (String path : paths) { + rt = rt.path(path); + } + if (isAuthorizationEnabled()) { + rt = rt.queryParam("user.name", webserviceUserName); + } + return rt; + } + + private WebResource constructWebResource(String... paths) { + WebResource r = resource(); + WebResource ws = r.path("ws").path("v1").path("cluster"); + return this.constructWebResource(ws, paths); + } + + @Test + public void testSingleAppState() throws Exception { + // this.client().addFilter(new LoggingFilter(System.out)); + rm.start(); + MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); + String[] mediaTypes = + { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }; + for (String mediaType : mediaTypes) { + RMApp app = rm.submitApp(CONTAINER_MB, "", webserviceUserName); + amNodeManager.nodeHeartbeat(true); + ClientResponse response = + this + .constructWebResource("apps", app.getApplicationId().toString(), + "state").accept(mediaType).get(ClientResponse.class); + assertEquals(Status.OK, response.getClientResponseStatus()); + if (mediaType == MediaType.APPLICATION_JSON) { + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + JSONObject json = response.getEntity(JSONObject.class); + assertEquals("incorrect number of elements", 1, json.length()); + String state = json.getString("state"); + assertEquals("app state incorrect", "ACCEPTED", state); + + } else if (mediaType == MediaType.APPLICATION_XML) { + assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType()); + String xml = response.getEntity(String.class); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + InputSource is = new InputSource(); + is.setCharacterStream(new StringReader(xml)); + Document dom = db.parse(is); + NodeList nodes = dom.getElementsByTagName("appstate"); + assertEquals("incorrect number of elements", 1, nodes.getLength()); + Element element = (Element) nodes.item(0); + String state = WebServicesTestUtils.getXmlString(element, "state"); + assertEquals("app state incorrect", "ACCEPTED", state); + } + } + rm.stop(); + } + + @Test(timeout = 90000) + public void testSingleAppKill() throws Exception { + rm.start(); + MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); + // this.client().addFilter(new LoggingFilter(System.out)); + String[] mediaTypes = + { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }; + MediaType[] contentTypes = + { MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE }; + for (String mediaType : mediaTypes) { + for (MediaType contentType : contentTypes) { + RMApp app = rm.submitApp(CONTAINER_MB, "", webserviceUserName); + amNodeManager.nodeHeartbeat(true); + + ClientResponse response = + this + .constructWebResource("apps", app.getApplicationId().toString(), + "state").accept(mediaType).get(ClientResponse.class); + AppState targetState = + new AppState(YarnApplicationState.KILLED.toString()); + + Object entity; + if (contentType == MediaType.APPLICATION_JSON_TYPE) { + entity = appStateToJSON(targetState); + } else { + entity = targetState; + } + response = + this + .constructWebResource("apps", app.getApplicationId().toString(), + "state").entity(entity, contentType).accept(mediaType) + .put(ClientResponse.class); + + if (!isAuthorizationEnabled()) { + assertEquals(Status.UNAUTHORIZED, response.getClientResponseStatus()); + continue; + } + assertEquals(Status.ACCEPTED, response.getClientResponseStatus()); + if (mediaType == MediaType.APPLICATION_JSON) { + verifyAppKillJson(response, RMAppState.ACCEPTED); + } else { + verifyAppKillXML(response, RMAppState.ACCEPTED); + } + + String locationHeaderValue = + response.getHeaders().getFirst(HttpHeaders.LOCATION); + Client c = Client.create(); + WebResource tmp = c.resource(locationHeaderValue); + if (isAuthorizationEnabled()) { + tmp = tmp.queryParam("user.name", webserviceUserName); + } + response = tmp.get(ClientResponse.class); + assertEquals(Status.OK, response.getClientResponseStatus()); + assertTrue(locationHeaderValue.endsWith("/ws/v1/cluster/apps/" + + app.getApplicationId().toString())); + + while (true) { + Thread.sleep(100); + response = + this + .constructWebResource("apps", + app.getApplicationId().toString(), "state").accept(mediaType) + .entity(entity, contentType).put(ClientResponse.class); + assertTrue((response.getClientResponseStatus() == Status.ACCEPTED) + || (response.getClientResponseStatus() == Status.OK)); + if (response.getClientResponseStatus() == Status.OK) { + if (mediaType == MediaType.APPLICATION_JSON) { + verifyAppKillJson(response, RMAppState.KILLED); + } else { + verifyAppKillXML(response, RMAppState.KILLED); + } + break; + } + } + } + } + + rm.stop(); + return; + } + + @Test + public void testSingleAppKillInvalidState() throws Exception { + // this.client().addFilter(new LoggingFilter(System.out)); + rm.start(); + MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); + + String[] mediaTypes = + { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }; + MediaType[] contentTypes = + { MediaType.APPLICATION_JSON_TYPE, MediaType.APPLICATION_XML_TYPE }; + String[] targetStates = + { YarnApplicationState.FINISHED.toString(), "blah" }; + + for (String mediaType : mediaTypes) { + for (MediaType contentType : contentTypes) { + for (String targetStateString : targetStates) { + RMApp app = rm.submitApp(CONTAINER_MB, "", webserviceUserName); + amNodeManager.nodeHeartbeat(true); + ClientResponse response; + AppState targetState = new AppState(targetStateString); + Object entity; + if (contentType == MediaType.APPLICATION_JSON_TYPE) { + entity = appStateToJSON(targetState); + } else { + entity = targetState; + } + response = + this + .constructWebResource("apps", + app.getApplicationId().toString(), "state") + .entity(entity, contentType).accept(mediaType) + .put(ClientResponse.class); + + if (!isAuthorizationEnabled()) { + assertEquals(Status.UNAUTHORIZED, + response.getClientResponseStatus()); + continue; + } + assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus()); + } + } + } + + rm.stop(); + return; + } + + private static String appStateToJSON(AppState state) throws Exception { + StringWriter sw = new StringWriter(); + JSONJAXBContext ctx = new JSONJAXBContext(AppState.class); + JSONMarshaller jm = ctx.createJSONMarshaller(); + jm.marshallToJSON(state, sw); + return sw.toString(); + } + protected static void verifyAppKillJson(ClientResponse response, + RMAppState state) throws JSONException { + + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + JSONObject json = response.getEntity(JSONObject.class); + assertEquals("incorrect number of elements", 1, json.length()); + JSONObject appObj = json.getJSONObject("app"); + assertEquals("app state incorrect", state.toString(), + appObj.getString("state")); + return; + } + + protected static void verifyAppKillXML(ClientResponse response, + RMAppState appState) throws ParserConfigurationException, IOException, + SAXException { + assertEquals(MediaType.APPLICATION_XML_TYPE, response.getType()); + String xml = response.getEntity(String.class); + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + InputSource is = new InputSource(); + is.setCharacterStream(new StringReader(xml)); + Document dom = db.parse(is); + NodeList nodes = dom.getElementsByTagName("app"); + assertEquals("incorrect number of elements", 1, nodes.getLength()); + Element element = (Element) nodes.item(0); + String state = WebServicesTestUtils.getXmlString(element, "state"); + assertEquals("app state incorrect", appState.toString(), state); + return; + } + + @Test(timeout = 30000) + public void testSingleAppKillUnauthorized() throws Exception { + // this.client().addFilter(new LoggingFilter(System.out)); + rm.start(); + MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); + + String[] mediaTypes = + { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }; + for (String mediaType : mediaTypes) { + RMApp app = rm.submitApp(CONTAINER_MB, "test", "someuser"); + amNodeManager.nodeHeartbeat(true); + ClientResponse response = + this + .constructWebResource("apps", app.getApplicationId().toString(), + "state").accept(mediaType).get(ClientResponse.class); + AppState info = response.getEntity(AppState.class); + info.setState(YarnApplicationState.KILLED.toString()); + + response = + this + .constructWebResource("apps", app.getApplicationId().toString(), + "state").accept(mediaType) + .entity(info, MediaType.APPLICATION_XML).put(ClientResponse.class); + if (!isAuthorizationEnabled()) { + assertEquals(Status.UNAUTHORIZED, response.getClientResponseStatus()); + } else { + assertEquals(Status.FORBIDDEN, response.getClientResponseStatus()); + } + } + + // there's a condition where if the rm is stopped while an app + // is being killed, it can lead to the test timing out, hence the sleep + Thread.sleep(3000); + + rm.stop(); + return; + + } + + @Test + public void testSingleAppKillInvalidId() throws Exception { + rm.start(); + MockNM amNodeManager = rm.registerNode("127.0.0.1:1234", 2048); + amNodeManager.nodeHeartbeat(true); + String[] testAppIds = { "application_1391705042196_0001", "random_string" }; + for (String testAppId : testAppIds) { + AppState info = new AppState("KILLED"); + ClientResponse response = + this.constructWebResource("apps", testAppId, "state") + .accept(MediaType.APPLICATION_XML) + .entity(info, MediaType.APPLICATION_XML).put(ClientResponse.class); + if (!isAuthorizationEnabled()) { + assertEquals(Status.UNAUTHORIZED, response.getClientResponseStatus()); + continue; + } + assertEquals(Status.NOT_FOUND, response.getClientResponseStatus()); + } + rm.stop(); + return; + } + + @After + @Override + public void tearDown() throws Exception { + if (rm != null) { + rm.stop(); + } + super.tearDown(); + } +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/ResourceManagerRest.apt.vm hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/ResourceManagerRest.apt.vm index ac6b446..4577f9f 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/ResourceManagerRest.apt.vm +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-site/src/site/apt/ResourceManagerRest.apt.vm @@ -1566,6 +1566,367 @@ _01_000001 +---+ +* Cluster Application State API + + With the application state API, you can query the state of a submitted app as well kill a running app by modifying the state of a running app using a PUT request with the state set to "KILLED". To perform the PUT operation, authentication has to be setup for the RM web services. In addition, you must be authorized to kill the app. Currently you can only change the state to "KILLED"; an attempt to change the state to any other results in a 400 error response. Examples of the unauthorized and bad request errors are below. When you carry out a successful PUT, the iniital response may be a 202. You can confirm that the app is killed by repeating the PUT request until you get a 200, querying the state using the GET method or querying for app information and checking the state. In the examples below, we repeat the PUT request and get a 200 response. + +** URI + +----- + * http:///ws/v1/cluster/apps/{appid}/state +----- + +** HTTP Operations Supported + +------ + * GET + * PUT +------ + +** Query Parameters Supported + +------ + None +------ + +** Elements of object + + When you make a request for the state of an app, the information returned has the following fields + +*---------------+--------------+-------------------------------+ +|| Item || Data Type || Description | +*---------------+--------------+-------------------------------+ +| state | string | The application state - can be one of "NEW", "NEW_SAVING", "SUBMITTED", "ACCEPTED", "RUNNING", "FINISHED", "FAILED", "KILLED" | +*---------------+--------------+--------------------------------+ + + +** Response Examples + + <> + + HTTP Request + +----- + GET http:///ws/v1/cluster/apps/application_1399397633663_0003/state +----- + + Response Header: + ++---+ +HTTP/1.1 200 OK +Content-Type: application/json +Transfer-Encoding: chunked +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ +{ + "state":"ACCEPTED" +} ++---+ + + HTTP Request + +----- + PUT http:///ws/v1/cluster/apps/application_1399397633663_0003/state +---- + + Request Body: + ++---+ +{ + "state":"KILLED" +} ++---+ + + Response Header: + ++---+ +HTTP/1.1 202 Accepted +Content-Type: application/json +Transfer-Encoding: chunked +Location: http:///ws/v1/cluster/apps/application_1399397633663_0003 +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ +{ + "app" : { + "id" : "application_1399397633663_0003", + "user" : "testuser", + "name" : "", + "queue" : "default", + "state" : "ACCEPTED", + "finalStatus" : "UNDEFINED", + "progress" : 0.0, + "trackingUI" : "UNASSIGNED", + "diagnostics" : "", + "clusterId" : 1399397633663, + "applicationType" : "YARN", + "applicationTags" : "", + "startedTime" : 1399399171088, + "finishedTime" : 0, + "elapsedTime" : 3001, + "amContainerLogs" : "http://127.0.0.1:2/node/containerlogs/container_1399399170898_0001_01_000001/testuser", + "amHostHttpAddress" : "127.0.0.1:2", + "allocatedMB" : 1024, + "allocatedVCores" : 1, + "runningContainers" : 1 + } +} ++---+ + +----- + PUT http:///ws/v1/cluster/apps/application_1399397633663_0003/state +---- + + Request Body: + ++---+ +{ + "state":"KILLED" +} ++---+ + + Response Header: + ++---+ +HTTP/1.1 200 OK +Content-Type: application/json +Transfer-Encoding: chunked +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ +{ + "app" : { + "id" : "application_1399397633663_0003", + "user" : "testuser", + "name" : "", + "queue" : "default", + "state" : "KILLED", + "finalStatus" : "KILLED", + "progress" : 0.0, + "trackingUI" : "History", + "trackingUrl" : "http://host.domain.come:port/cluster/app/application_1399397633663_0003", + "diagnostics" : "Application killed by user.", + "clusterId" : 1399397633663, + "applicationType" : "YARN", + "applicationTags" : "", + "startedTime" : 1399400153117, + "finishedTime" : 1399400155892, + "elapsedTime" : 2775, + "amContainerLogs" : "http://host.domain.com:port/node/containerlogs/container_1399400153011_0001_01_000001/testuser", + "amHostHttpAddress" : "host.domain.com:port", + "allocatedMB" : 0, + "allocatedVCores" : 0, + "runningContainers" : 0 + } +} ++---+ + + <> + + HTTP Request + +----- + GET http:///ws/v1/cluster/apps/application_1399397633663_0003/state +----- + + Response Header: + ++---+ +HTTP/1.1 200 OK +Content-Type: application/xml +Content-Length: 99 +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ + + + ACCEPTED + ++---+ + + HTTP Request + +----- + PUT http:///ws/v1/cluster/apps/application_1399397633663_0003/state +---- + + Request Body: + ++---+ + + + KILLED + ++---+ + + Response Header: + ++---+ +HTTP/1.1 202 Accepted +Content-Type: application/json +Content-Length: 794 +Location: http:///ws/v1/cluster/apps/application_1399397633663_0003 +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ + + + application_1399397633663_0003 + testuser + + default + ACCEPTED + UNDEFINED + 0.0 + UNASSIGNED + + 1399397633663 + YARN + + 1399399176143 + 0 + 2018 + http://host.domain.com:port/node/containerlogs/container_1399399170898_0003_01_000001/testuser + host.domain.com:port + 1024 + 1 + 1 + ++---+ + + HTTP Request + +----- + PUT http:///ws/v1/cluster/apps/application_1399397633663_0003/state +---- + + Request Body: + ++---+ + + + KILLED + ++---+ + + Response Header: + ++---+ +HTTP/1.1 200 OK +Content-Type: application/xml +Content-Length: 917 +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ + + + application_1399397633663_0003 + testuser + + default + KILLED + KILLED + 0.0 + History + http://host.domain.com:port/cluster/app/application_1399397633663_0003 + Application killed by user. + 1399397633663 + YARN + + 1399400158298 + 1399400160315 + 2017 + http://host.domain.com:port/node/containerlogs/container_1399400153011_0003_01_000001/testuser + host.domain.com:port + 0 + 0 + 0 + ++---+ + + <> + + HTTP Request + +----- + PUT http:///ws/v1/cluster/apps/application_1399397633663_0003/state +---- + + Request Body: + ++---+ + + + KILLED + ++---+ + + Response Header: + ++---+ +HTTP/1.1 403 Unauthorized +Content-Type: application/json +Transfer-Encoding: chunked +Server: Jetty(6.1.26) ++---+ + + + <> + + HTTP Request + +----- + PUT http:///ws/v1/cluster/apps/application_1399397633663_0003/state +---- + + Request Body: + ++---+ + + + RUNNING + ++---+ + + Response Header: + ++---+ +HTTP/1.1 400 +Content-Length: 295 +Content-Type: application/xml +Server: Jetty(6.1.26) ++---+ + + Response Body: + ++---+ + + + BadRequestException + java.lang.Exception: Only 'KILLED' is allowed as a target state. + org.apache.hadoop.yarn.webapp.BadRequestException + ++---+ + * Cluster Application Attempts API With the application attempts API, you can obtain a collection of resources that represent an application attempt. When you run a GET operation on this resource, you obtain a collection of App Attempt Objects.