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 5d339c46f5b16b951afd82afd9e907b9aa2ded9a)
This commit is contained in:
parent
da944fe0f4
commit
83a5896180
@ -369,6 +369,16 @@ private void addTimelineDelegationToken(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
throw e;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,26 +155,6 @@ public void testClientStop() {
|
|||||||
rm.stop();
|
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
|
@Test
|
||||||
public void testStartWithTimelineV15() throws Exception {
|
public void testStartWithTimelineV15() throws Exception {
|
||||||
Configuration conf = new Configuration();
|
Configuration conf = new Configuration();
|
||||||
@ -186,6 +166,89 @@ public void testStartWithTimelineV15() throws Exception {
|
|||||||
client.stop();
|
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")
|
@SuppressWarnings("deprecation")
|
||||||
@Test (timeout = 30000)
|
@Test (timeout = 30000)
|
||||||
public void testSubmitApplication() throws Exception {
|
public void testSubmitApplication() throws Exception {
|
||||||
@ -1677,4 +1740,66 @@ public void testSignalContainer() throws Exception {
|
|||||||
Assert.assertEquals(containerId, request.getContainerId());
|
Assert.assertEquals(containerId, request.getContainerId());
|
||||||
Assert.assertEquals(command, request.getCommand());
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user