YARN-5309. Fix SSLFactory truststore reloader thread leak in TimelineClientImpl. Contributed by Weiwei Yang.
This commit is contained in:
parent
8fbe6ece24
commit
9ccf935b2c
|
@ -150,6 +150,11 @@
|
|||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcprov-jdk16</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.jersey-test-framework</groupId>
|
||||
<artifactId>jersey-test-framework-grizzly2</artifactId>
|
||||
|
|
|
@ -125,6 +125,7 @@ public class TimelineClientImpl extends TimelineClient {
|
|||
private Configuration configuration;
|
||||
private float timelineServiceVersion;
|
||||
private TimelineWriter timelineWriter;
|
||||
private SSLFactory sslFactory;
|
||||
|
||||
private volatile String timelineServiceAddress;
|
||||
|
||||
|
@ -298,7 +299,7 @@ public class TimelineClientImpl extends TimelineClient {
|
|||
}
|
||||
ClientConfig cc = new DefaultClientConfig();
|
||||
cc.getClasses().add(YarnJacksonJaxbJsonProvider.class);
|
||||
connConfigurator = newConnConfigurator(conf);
|
||||
connConfigurator = initConnConfigurator(conf);
|
||||
if (UserGroupInformation.isSecurityEnabled()) {
|
||||
authenticator = new KerberosDelegationTokenAuthenticator();
|
||||
} else {
|
||||
|
@ -373,6 +374,9 @@ public class TimelineClientImpl extends TimelineClient {
|
|||
if (timelineServiceV2) {
|
||||
entityDispatcher.stop();
|
||||
}
|
||||
if (this.sslFactory != null) {
|
||||
this.sslFactory.destroy();
|
||||
}
|
||||
super.serviceStop();
|
||||
}
|
||||
|
||||
|
@ -672,9 +676,9 @@ public class TimelineClientImpl extends TimelineClient {
|
|||
|
||||
}
|
||||
|
||||
private static ConnectionConfigurator newConnConfigurator(Configuration conf) {
|
||||
private ConnectionConfigurator initConnConfigurator(Configuration conf) {
|
||||
try {
|
||||
return newSslConnConfigurator(DEFAULT_SOCKET_TIMEOUT, conf);
|
||||
return initSslConnConfigurator(DEFAULT_SOCKET_TIMEOUT, conf);
|
||||
} catch (Exception e) {
|
||||
LOG.debug("Cannot load customized ssl related configuration. " +
|
||||
"Fallback to system-generic settings.", e);
|
||||
|
@ -692,16 +696,15 @@ public class TimelineClientImpl extends TimelineClient {
|
|||
}
|
||||
};
|
||||
|
||||
private static ConnectionConfigurator newSslConnConfigurator(final int timeout,
|
||||
private ConnectionConfigurator initSslConnConfigurator(final int timeout,
|
||||
Configuration conf) throws IOException, GeneralSecurityException {
|
||||
final SSLFactory factory;
|
||||
final SSLSocketFactory sf;
|
||||
final HostnameVerifier hv;
|
||||
|
||||
factory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
|
||||
factory.init();
|
||||
sf = factory.createSSLSocketFactory();
|
||||
hv = factory.getHostnameVerifier();
|
||||
sslFactory = new SSLFactory(SSLFactory.Mode.CLIENT, conf);
|
||||
sslFactory.init();
|
||||
sf = sslFactory.createSSLSocketFactory();
|
||||
hv = sslFactory.getHostnameVerifier();
|
||||
|
||||
return new ConnectionConfigurator() {
|
||||
@Override
|
||||
|
|
|
@ -25,6 +25,7 @@ import static org.mockito.Mockito.mock;
|
|||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.SocketTimeoutException;
|
||||
|
@ -35,8 +36,10 @@ import org.apache.hadoop.conf.Configuration;
|
|||
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
|
||||
import org.apache.hadoop.io.Text;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
|
||||
import org.apache.hadoop.security.token.Token;
|
||||
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSecretManager;
|
||||
import org.apache.hadoop.test.TestGenericTestUtils;
|
||||
import org.apache.hadoop.yarn.api.records.timeline.TimelineDomain;
|
||||
import org.apache.hadoop.yarn.api.records.timeline.TimelineEntities;
|
||||
import org.apache.hadoop.yarn.api.records.timeline.TimelineEntity;
|
||||
|
@ -434,6 +437,50 @@ public class TestTimelineClient {
|
|||
return client;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimelineClientCleanup() throws Exception {
|
||||
YarnConfiguration conf = new YarnConfiguration();
|
||||
conf.setBoolean(YarnConfiguration.TIMELINE_SERVICE_ENABLED, true);
|
||||
conf.setInt(YarnConfiguration.TIMELINE_SERVICE_CLIENT_MAX_RETRIES, 0);
|
||||
|
||||
File testDir = TestGenericTestUtils.getTestDir();
|
||||
String sslConfDir =
|
||||
KeyStoreTestUtil.getClasspathDir(TestTimelineClient.class);
|
||||
KeyStoreTestUtil.setupSSLConfig(testDir.getAbsolutePath(),
|
||||
sslConfDir, conf, false);
|
||||
client = createTimelineClient(conf);
|
||||
|
||||
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
|
||||
|
||||
while (threadGroup.getParent() != null) {
|
||||
threadGroup = threadGroup.getParent();
|
||||
}
|
||||
|
||||
Thread[] threads = new Thread[threadGroup.activeCount()];
|
||||
|
||||
threadGroup.enumerate(threads);
|
||||
Thread reloaderThread = null;
|
||||
for (Thread thread : threads) {
|
||||
if ((thread.getName() != null)
|
||||
&& (thread.getName().contains("Truststore reloader thread"))) {
|
||||
reloaderThread = thread;
|
||||
}
|
||||
}
|
||||
Assert.assertTrue("Reloader is not alive", reloaderThread.isAlive());
|
||||
|
||||
client.close();
|
||||
|
||||
boolean reloaderStillAlive = true;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
reloaderStillAlive = reloaderThread.isAlive();
|
||||
if (!reloaderStillAlive) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
Assert.assertFalse("Reloader is still alive", reloaderStillAlive);
|
||||
}
|
||||
|
||||
private static class TestTimlineDelegationTokenSecretManager extends
|
||||
AbstractDelegationTokenSecretManager<TimelineDelegationTokenIdentifier> {
|
||||
|
||||
|
|
Loading…
Reference in New Issue