YARN-6177. Yarn client should exit with an informative error message if an incompatible Jersey library is used at client. Contributed by Weiwei Yang.

(cherry picked from commit 5d339c46f5)
This commit is contained in:
Li Lu 2017-02-16 13:40:26 -08:00
parent f07b52dc5a
commit 8fc67e5973
2 changed files with 155 additions and 20 deletions

View File

@ -376,6 +376,16 @@ public class YarnClientImpl extends YarnClient {
return null;
}
throw e;
} catch (NoClassDefFoundError e) {
NoClassDefFoundError wrappedError = new NoClassDefFoundError(
e.getMessage() + ". It appears that the timeline client "
+ "failed to initiate because an incompatible dependency "
+ "in classpath. If timeline service is optional to this "
+ "client, try to work around by setting "
+ YarnConfiguration.TIMELINE_SERVICE_ENABLED
+ " to false in client configuration.");
wrappedError.setStackTrace(e.getStackTrace());
throw wrappedError;
}
}

View File

@ -155,26 +155,6 @@ public class TestYarnClient {
rm.stop();
}
@Test
public void testStartWithTimelineV15Failure() throws Exception{
Configuration conf = new Configuration();
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_ENABLED, true);
conf.setFloat(YarnConfiguration.TIMELINE_SERVICE_VERSION, 1.5f);
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_CLIENT_BEST_EFFORT,
true);
YarnClient client = YarnClient.createYarnClient();
if(client instanceof YarnClientImpl) {
YarnClientImpl impl = (YarnClientImpl) client;
YarnClientImpl spyClient = spy(impl);
when(spyClient.createTimelineClient()).thenThrow(
new IOException("ATS v1.5 client initialization failed. "));
spyClient.init(conf);
spyClient.start();
spyClient.getTimelineDelegationToken();
spyClient.stop();
}
}
@Test
public void testStartWithTimelineV15() throws Exception {
Configuration conf = new Configuration();
@ -186,6 +166,89 @@ public class TestYarnClient {
client.stop();
}
@Test
public void testStartTimelineClientWithErrors()
throws Exception {
// If timeline client failed to init with a NoClassDefFoundError
// it should be wrapped with an informative error message
testCreateTimelineClientWithError(
1.5f,
true,
false,
new NoClassDefFoundError("Mock a NoClassDefFoundError"),
new CreateTimelineClientErrorVerifier(1) {
@Override
public void verifyError(Throwable e) {
Assert.assertTrue(e instanceof NoClassDefFoundError);
Assert.assertTrue(e.getMessage() != null &&
e.getMessage().contains(
YarnConfiguration.TIMELINE_SERVICE_ENABLED));
}
});
// Disable timeline service for this client,
// yarn client will not fail when such error happens
testCreateTimelineClientWithError(
1.5f,
false,
false,
new NoClassDefFoundError("Mock a NoClassDefFoundError"),
new CreateTimelineClientErrorVerifier(0) {
@Override public void verifyError(Throwable e) {
Assert.fail("NoClassDefFoundError while creating timeline client"
+ "should be tolerated when timeline service is disabled.");
}
}
);
// Set best-effort to true, verify an error is still fatal
testCreateTimelineClientWithError(
1.5f,
true,
true,
new NoClassDefFoundError("Mock a NoClassDefFoundError"),
new CreateTimelineClientErrorVerifier(1) {
@Override public void verifyError(Throwable e) {
Assert.assertTrue(e instanceof NoClassDefFoundError);
Assert.assertTrue(e.getMessage() != null &&
e.getMessage().contains(
YarnConfiguration.TIMELINE_SERVICE_ENABLED));
}
}
);
// Set best-effort to false, verify that an exception
// causes the client to fail
testCreateTimelineClientWithError(
1.5f,
true,
false,
new IOException("ATS v1.5 client initialization failed."),
new CreateTimelineClientErrorVerifier(1) {
@Override
public void verifyError(Throwable e) {
Assert.assertTrue(e instanceof IOException);
}
}
);
// Set best-effort to true, verify that an normal exception
// won't fail the entire client
testCreateTimelineClientWithError(
1.5f,
true,
true,
new IOException("ATS v1.5 client initialization failed."),
new CreateTimelineClientErrorVerifier(0) {
@Override
public void verifyError(Throwable e) {
Assert.fail("IOException while creating timeline client"
+ "should be tolerated when best effort is true");
}
}
);
}
@SuppressWarnings("deprecation")
@Test (timeout = 30000)
public void testSubmitApplication() throws Exception {
@ -1680,4 +1743,66 @@ public class TestYarnClient {
Assert.assertEquals(containerId, request.getContainerId());
Assert.assertEquals(command, request.getCommand());
}
private void testCreateTimelineClientWithError(
float timelineVersion,
boolean timelineServiceEnabled,
boolean timelineClientBestEffort,
Throwable mockErr,
CreateTimelineClientErrorVerifier errVerifier) throws Exception {
Configuration conf = new Configuration();
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_ENABLED,
timelineServiceEnabled);
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_CLIENT_BEST_EFFORT,
timelineClientBestEffort);
conf.setFloat(YarnConfiguration.TIMELINE_SERVICE_VERSION,
timelineVersion);
YarnClient client = new MockYarnClient();
if (client instanceof YarnClientImpl) {
YarnClientImpl impl = (YarnClientImpl) client;
YarnClientImpl spyClient = spy(impl);
when(spyClient.createTimelineClient()).thenThrow(mockErr);
CreateTimelineClientErrorVerifier verifier = spy(errVerifier);
spyClient.init(conf);
spyClient.start();
ApplicationSubmissionContext context =
mock(ApplicationSubmissionContext.class);
ContainerLaunchContext containerContext =
mock(ContainerLaunchContext.class);
ApplicationId applicationId =
ApplicationId.newInstance(System.currentTimeMillis(), 1);
when(containerContext.getTokens()).thenReturn(null);
when(context.getApplicationId()).thenReturn(applicationId);
when(spyClient.isSecurityEnabled()).thenReturn(true);
when(context.getAMContainerSpec()).thenReturn(containerContext);
try {
spyClient.submitApplication(context);
} catch (Throwable e) {
verifier.verifyError(e);
} finally {
// Make sure the verifier runs with expected times
// This is required because in case throwable is swallowed
// and verifyError never gets the chance to run
verify(verifier, times(verifier.getExpectedTimes()))
.verifyError(any(Throwable.class));
spyClient.stop();
}
}
}
private abstract class CreateTimelineClientErrorVerifier {
// Verify verifyError gets executed with expected times
private int times = 0;
protected CreateTimelineClientErrorVerifier(int times) {
this.times = times;
}
public int getExpectedTimes() {
return this.times;
}
// Verification a throwable is in desired state
// E.g verify type and error message
public abstract void verifyError(Throwable e);
}
}