svn merge -c 1308566 from trunk. FIXES MAPREDUCE-4024. RM webservices can't query on finalStatus (Tom Graves via bobby)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1308568 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ad9f93f7b5
commit
97f328dc40
|
@ -116,6 +116,9 @@ Release 0.23.3 - UNRELEASED
|
||||||
|
|
||||||
MAPREDUCE-4089. Hung Tasks never time out. (Robert Evans via tgraves)
|
MAPREDUCE-4089. Hung Tasks never time out. (Robert Evans via tgraves)
|
||||||
|
|
||||||
|
MAPREDUCE-4024. RM webservices can't query on finalStatus (Tom Graves
|
||||||
|
via bobby)
|
||||||
|
|
||||||
Release 0.23.2 - UNRELEASED
|
Release 0.23.2 - UNRELEASED
|
||||||
|
|
||||||
INCOMPATIBLE CHANGES
|
INCOMPATIBLE CHANGES
|
||||||
|
|
|
@ -31,6 +31,7 @@ import javax.ws.rs.core.UriInfo;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.mapreduce.v2.api.records.AMInfo;
|
import org.apache.hadoop.mapreduce.v2.api.records.AMInfo;
|
||||||
|
import org.apache.hadoop.mapreduce.v2.api.records.JobState;
|
||||||
import org.apache.hadoop.mapreduce.v2.api.records.JobReport;
|
import org.apache.hadoop.mapreduce.v2.api.records.JobReport;
|
||||||
import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
|
import org.apache.hadoop.mapreduce.v2.api.records.TaskId;
|
||||||
import org.apache.hadoop.mapreduce.v2.api.records.TaskType;
|
import org.apache.hadoop.mapreduce.v2.api.records.TaskType;
|
||||||
|
@ -96,6 +97,7 @@ public class HsWebServices {
|
||||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||||
public JobsInfo getJobs(@QueryParam("user") String userQuery,
|
public JobsInfo getJobs(@QueryParam("user") String userQuery,
|
||||||
@QueryParam("limit") String count,
|
@QueryParam("limit") String count,
|
||||||
|
@QueryParam("state") String stateQuery,
|
||||||
@QueryParam("queue") String queueQuery,
|
@QueryParam("queue") String queueQuery,
|
||||||
@QueryParam("startedTimeBegin") String startedBegin,
|
@QueryParam("startedTimeBegin") String startedBegin,
|
||||||
@QueryParam("startedTimeEnd") String startedEnd,
|
@QueryParam("startedTimeEnd") String startedEnd,
|
||||||
|
@ -185,6 +187,13 @@ public class HsWebServices {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (stateQuery != null && !stateQuery.isEmpty()) {
|
||||||
|
JobState.valueOf(stateQuery);
|
||||||
|
if (!job.getState().toString().equalsIgnoreCase(stateQuery)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// can't really validate queue is a valid one since queues could change
|
// can't really validate queue is a valid one since queues could change
|
||||||
if (queueQuery != null && !queueQuery.isEmpty()) {
|
if (queueQuery != null && !queueQuery.isEmpty()) {
|
||||||
if (!job.getQueueName().equals(queueQuery)) {
|
if (!job.getQueueName().equals(queueQuery)) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.mapreduce.v2.api.records.JobId;
|
import org.apache.hadoop.mapreduce.v2.api.records.JobId;
|
||||||
|
import org.apache.hadoop.mapreduce.v2.api.records.JobState;
|
||||||
import org.apache.hadoop.mapreduce.v2.app.AppContext;
|
import org.apache.hadoop.mapreduce.v2.app.AppContext;
|
||||||
import org.apache.hadoop.mapreduce.v2.app.MockJobs;
|
import org.apache.hadoop.mapreduce.v2.app.MockJobs;
|
||||||
import org.apache.hadoop.mapreduce.v2.app.job.Job;
|
import org.apache.hadoop.mapreduce.v2.app.job.Job;
|
||||||
|
@ -195,6 +196,72 @@ public class TestHsWebServicesJobsQuery extends JerseyTest {
|
||||||
.contextPath("jersey-guice-filter").servletPath("/").build());
|
.contextPath("jersey-guice-filter").servletPath("/").build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJobsQueryStateNone() throws JSONException, Exception {
|
||||||
|
WebResource r = resource();
|
||||||
|
ClientResponse response = r.path("ws").path("v1").path("history")
|
||||||
|
.path("mapreduce").path("jobs").queryParam("state", JobState.KILL_WAIT.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());
|
||||||
|
assertEquals("jobs is not null", JSONObject.NULL, json.get("jobs"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJobsQueryState() throws JSONException, Exception {
|
||||||
|
WebResource r = resource();
|
||||||
|
// we only create 3 jobs and it cycles through states so we should have 3 unique states
|
||||||
|
Map<JobId, Job> jobsMap = appContext.getAllJobs();
|
||||||
|
String queryState = "BOGUS";
|
||||||
|
JobId jid = null;
|
||||||
|
for (Map.Entry<JobId, Job> entry : jobsMap.entrySet()) {
|
||||||
|
jid = entry.getValue().getID();
|
||||||
|
queryState = entry.getValue().getState().toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ClientResponse response = r.path("ws").path("v1").path("history")
|
||||||
|
.path("mapreduce").path("jobs").queryParam("state", queryState)
|
||||||
|
.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());
|
||||||
|
JSONObject jobs = json.getJSONObject("jobs");
|
||||||
|
JSONArray arr = jobs.getJSONArray("job");
|
||||||
|
assertEquals("incorrect number of elements", 1, arr.length());
|
||||||
|
JSONObject info = arr.getJSONObject(0);
|
||||||
|
Job job = appContext.getPartialJob(jid);
|
||||||
|
VerifyJobsUtils.verifyHsJobPartial(info, job);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJobsQueryStateInvalid() throws JSONException, Exception {
|
||||||
|
WebResource r = resource();
|
||||||
|
|
||||||
|
ClientResponse response = r.path("ws").path("v1").path("history")
|
||||||
|
.path("mapreduce").path("jobs").queryParam("state", "InvalidState")
|
||||||
|
.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
|
||||||
|
|
||||||
|
assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus());
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
JSONObject msg = response.getEntity(JSONObject.class);
|
||||||
|
JSONObject exception = msg.getJSONObject("RemoteException");
|
||||||
|
assertEquals("incorrect number of elements", 3, exception.length());
|
||||||
|
String message = exception.getString("message");
|
||||||
|
String type = exception.getString("exception");
|
||||||
|
String classname = exception.getString("javaClassName");
|
||||||
|
WebServicesTestUtils
|
||||||
|
.checkStringMatch(
|
||||||
|
"exception message",
|
||||||
|
"No enum const class org.apache.hadoop.mapreduce.v2.api.records.JobState.InvalidState",
|
||||||
|
message);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception type",
|
||||||
|
"IllegalArgumentException", type);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception classname",
|
||||||
|
"java.lang.IllegalArgumentException", classname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJobsQueryUserNone() throws JSONException, Exception {
|
public void testJobsQueryUserNone() throws JSONException, Exception {
|
||||||
WebResource r = resource();
|
WebResource r = resource();
|
||||||
|
@ -215,6 +282,8 @@ public class TestHsWebServicesJobsQuery extends JerseyTest {
|
||||||
.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
|
.accept(MediaType.APPLICATION_JSON).get(ClientResponse.class);
|
||||||
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
JSONObject json = response.getEntity(JSONObject.class);
|
JSONObject json = response.getEntity(JSONObject.class);
|
||||||
|
System.out.println(json.toString());
|
||||||
|
|
||||||
assertEquals("incorrect number of elements", 1, json.length());
|
assertEquals("incorrect number of elements", 1, json.length());
|
||||||
JSONObject jobs = json.getJSONObject("jobs");
|
JSONObject jobs = json.getJSONObject("jobs");
|
||||||
JSONArray arr = jobs.getJSONArray("job");
|
JSONArray arr = jobs.getJSONArray("job");
|
||||||
|
|
|
@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationAccessType;
|
import org.apache.hadoop.yarn.api.records.ApplicationAccessType;
|
||||||
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
import org.apache.hadoop.yarn.api.records.ApplicationId;
|
||||||
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
import org.apache.hadoop.yarn.api.records.NodeId;
|
import org.apache.hadoop.yarn.api.records.NodeId;
|
||||||
import org.apache.hadoop.yarn.factories.RecordFactory;
|
import org.apache.hadoop.yarn.factories.RecordFactory;
|
||||||
import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider;
|
import org.apache.hadoop.yarn.factory.providers.RecordFactoryProvider;
|
||||||
|
@ -225,6 +226,7 @@ public class RMWebServices {
|
||||||
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
|
||||||
public AppsInfo getApps(@Context HttpServletRequest hsr,
|
public AppsInfo getApps(@Context HttpServletRequest hsr,
|
||||||
@QueryParam("state") String stateQuery,
|
@QueryParam("state") String stateQuery,
|
||||||
|
@QueryParam("finalStatus") String finalStatusQuery,
|
||||||
@QueryParam("user") String userQuery,
|
@QueryParam("user") String userQuery,
|
||||||
@QueryParam("queue") String queueQuery,
|
@QueryParam("queue") String queueQuery,
|
||||||
@QueryParam("limit") String count,
|
@QueryParam("limit") String count,
|
||||||
|
@ -294,19 +296,25 @@ public class RMWebServices {
|
||||||
.getRMApps();
|
.getRMApps();
|
||||||
AppsInfo allApps = new AppsInfo();
|
AppsInfo allApps = new AppsInfo();
|
||||||
for (RMApp rmapp : apps.values()) {
|
for (RMApp rmapp : apps.values()) {
|
||||||
|
|
||||||
if (checkCount && num == countNum) {
|
if (checkCount && num == countNum) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
AppInfo app = new AppInfo(rmapp, hasAccess(rmapp, hsr));
|
|
||||||
|
|
||||||
if (stateQuery != null && !stateQuery.isEmpty()) {
|
if (stateQuery != null && !stateQuery.isEmpty()) {
|
||||||
RMAppState.valueOf(stateQuery);
|
RMAppState.valueOf(stateQuery);
|
||||||
if (!app.getState().equalsIgnoreCase(stateQuery)) {
|
if (!rmapp.getState().toString().equalsIgnoreCase(stateQuery)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (finalStatusQuery != null && !finalStatusQuery.isEmpty()) {
|
||||||
|
FinalApplicationStatus.valueOf(finalStatusQuery);
|
||||||
|
if (!rmapp.getFinalApplicationStatus().toString()
|
||||||
|
.equalsIgnoreCase(finalStatusQuery)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (userQuery != null && !userQuery.isEmpty()) {
|
if (userQuery != null && !userQuery.isEmpty()) {
|
||||||
if (!app.getUser().equals(userQuery)) {
|
if (!rmapp.getUser().equals(userQuery)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,19 +329,20 @@ public class RMWebServices {
|
||||||
throw new BadRequestException(e.getMessage());
|
throw new BadRequestException(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!app.getQueue().equals(queueQuery)) {
|
if (!rmapp.getQueue().equals(queueQuery)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkStart
|
if (checkStart
|
||||||
&& (app.getStartTime() < sBegin || app.getStartTime() > sEnd)) {
|
&& (rmapp.getStartTime() < sBegin || rmapp.getStartTime() > sEnd)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (checkEnd
|
if (checkEnd
|
||||||
&& (app.getFinishTime() < fBegin || app.getFinishTime() > fEnd)) {
|
&& (rmapp.getFinishTime() < fBegin || rmapp.getFinishTime() > fEnd)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
AppInfo app = new AppInfo(rmapp, hasAccess(rmapp, hsr));
|
||||||
|
|
||||||
allApps.add(app);
|
allApps.add(app);
|
||||||
num++;
|
num++;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.security.UserGroupInformation;
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
|
import org.apache.hadoop.yarn.api.records.FinalApplicationStatus;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.MockAM;
|
import org.apache.hadoop.yarn.server.resourcemanager.MockAM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.MockNM;
|
import org.apache.hadoop.yarn.server.resourcemanager.MockNM;
|
||||||
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
|
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
|
||||||
|
@ -280,6 +281,85 @@ public class TestRMWebServicesApps extends JerseyTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppsQueryFinalStatus() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
RMApp app1 = rm.submitApp(1024);
|
||||||
|
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);
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
JSONObject json = response.getEntity(JSONObject.class);
|
||||||
|
assertEquals("incorrect number of elements", 1, json.length());
|
||||||
|
System.out.println(json.toString());
|
||||||
|
JSONObject apps = json.getJSONObject("apps");
|
||||||
|
assertEquals("incorrect number of elements", 1, apps.length());
|
||||||
|
JSONArray array = apps.getJSONArray("app");
|
||||||
|
assertEquals("incorrect number of elements", 1, array.length());
|
||||||
|
verifyAppInfo(array.getJSONObject(0), app1);
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppsQueryFinalStatusNone() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
rm.submitApp(1024);
|
||||||
|
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);
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
JSONObject json = response.getEntity(JSONObject.class);
|
||||||
|
assertEquals("incorrect number of elements", 1, json.length());
|
||||||
|
assertEquals("apps is not null", JSONObject.NULL, json.get("apps"));
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAppsQueryFinalStatusInvalid() throws JSONException, Exception {
|
||||||
|
rm.start();
|
||||||
|
MockNM amNodeManager = rm.registerNode("amNM:1234", 2048);
|
||||||
|
rm.submitApp(1024);
|
||||||
|
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);
|
||||||
|
fail("should have thrown exception on invalid state query");
|
||||||
|
} catch (UniformInterfaceException ue) {
|
||||||
|
ClientResponse response = ue.getResponse();
|
||||||
|
assertEquals(Status.BAD_REQUEST, response.getClientResponseStatus());
|
||||||
|
assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType());
|
||||||
|
JSONObject msg = response.getEntity(JSONObject.class);
|
||||||
|
JSONObject exception = msg.getJSONObject("RemoteException");
|
||||||
|
assertEquals("incorrect number of elements", 3, exception.length());
|
||||||
|
String message = exception.getString("message");
|
||||||
|
String type = exception.getString("exception");
|
||||||
|
String classname = exception.getString("javaClassName");
|
||||||
|
WebServicesTestUtils
|
||||||
|
.checkStringMatch(
|
||||||
|
"exception message",
|
||||||
|
"No enum const class org.apache.hadoop.yarn.api.records.FinalApplicationStatus.INVALID_test",
|
||||||
|
message);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception type",
|
||||||
|
"IllegalArgumentException", type);
|
||||||
|
WebServicesTestUtils.checkStringMatch("exception classname",
|
||||||
|
"java.lang.IllegalArgumentException", classname);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
rm.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAppsQueryUser() throws JSONException, Exception {
|
public void testAppsQueryUser() throws JSONException, Exception {
|
||||||
rm.start();
|
rm.start();
|
||||||
|
|
|
@ -149,6 +149,7 @@ History Server REST API's.
|
||||||
|
|
||||||
------
|
------
|
||||||
* user - user name
|
* user - user name
|
||||||
|
* state - the job state
|
||||||
* queue - queue name
|
* queue - queue name
|
||||||
* limit - total number of app objects to be returned
|
* limit - total number of app objects to be returned
|
||||||
* startedTimeBegin - jobs with start time beginning with this time, specified in ms since epoch
|
* startedTimeBegin - jobs with start time beginning with this time, specified in ms since epoch
|
||||||
|
|
|
@ -890,6 +890,7 @@ ResourceManager REST API's.
|
||||||
|
|
||||||
------
|
------
|
||||||
* state - state of the application
|
* state - state of the application
|
||||||
|
* finalStatus - the final status of the application - reported by the application itself
|
||||||
* user - user name
|
* user - user name
|
||||||
* queue - queue name
|
* queue - queue name
|
||||||
* limit - total number of app objects to be returned
|
* limit - total number of app objects to be returned
|
||||||
|
|
Loading…
Reference in New Issue