Add await busy loop for SimpleKdcLdapServer initialization (#39221) (#39342)

There have been intermittent failures where either
LDAP server could not be started or KDC server could
not be started causing failures during test runs.

`KdcNetwork` class from Apache kerby project does not set reuse
address to `true` on the socket so if the port that we found to be free
is in `TIME_WAIT` state it may fail to bind. As this is an internal
class for kerby, I could not find a way to extend.

This commit adds a retry loop for initialization. It will keep
trying in an await busy loop and fail after 10 seconds if not
initialized.

Closes #35982
This commit is contained in:
Yogesh Gaikwad 2019-02-25 20:35:08 +11:00 committed by GitHub
parent 96c09b032d
commit 7021e1bd3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -90,7 +90,9 @@ public class SimpleKdcLdapServer {
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
@Override @Override
public Void run() throws Exception { public Void run() throws Exception {
init(); if (ESTestCase.awaitBusy(() -> init()) == false) {
throw new IllegalStateException("could not initialize SimpleKdcLdapServer");
}
return null; return null;
} }
}); });
@ -98,14 +100,33 @@ public class SimpleKdcLdapServer {
} }
@SuppressForbidden(reason = "Uses Apache Kdc which requires usage of java.io.File in order to create a SimpleKdcServer") @SuppressForbidden(reason = "Uses Apache Kdc which requires usage of java.io.File in order to create a SimpleKdcServer")
private void init() throws Exception { private boolean init() {
// start ldap server boolean initialized = false;
createLdapServiceAndStart(); try {
// create ldap backend conf // start ldap server
createLdapBackendConf(); createLdapServiceAndStart();
// Kdc Server // create ldap backend conf
simpleKdc = new SimpleKdcServer(this.workDir.toFile(), new KrbConfig()); createLdapBackendConf();
prepareKdcServerAndStart(); // Kdc Server
simpleKdc = new SimpleKdcServer(this.workDir.toFile(), new KrbConfig());
prepareKdcServerAndStart();
initialized = true;
} catch (Exception e) {
if (simpleKdc != null) {
try {
simpleKdc.stop();
} catch (KrbException krbException) {
logger.debug("error occurred while cleaning up after init failure for SimpleKdcLdapServer");
}
}
if (ldapServer != null) {
ldapServer.shutDown(true);
}
ldapPort = 0;
kdcPort = 0;
initialized = false;
}
return initialized;
} }
private void createLdapServiceAndStart() throws Exception { private void createLdapServiceAndStart() throws Exception {
@ -229,12 +250,14 @@ public class SimpleKdcLdapServer {
if (transport != null && transport.trim().equalsIgnoreCase("TCP")) { if (transport != null && transport.trim().equalsIgnoreCase("TCP")) {
try (ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0, 1, try (ServerSocket serverSocket = ServerSocketFactory.getDefault().createServerSocket(0, 1,
InetAddress.getByName("127.0.0.1"))) { InetAddress.getByName("127.0.0.1"))) {
serverSocket.setReuseAddress(true);
return serverSocket.getLocalPort(); return serverSocket.getLocalPort();
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException("Failed to get a TCP server socket point"); throw new RuntimeException("Failed to get a TCP server socket point");
} }
} else if (transport != null && transport.trim().equalsIgnoreCase("UDP")) { } else if (transport != null && transport.trim().equalsIgnoreCase("UDP")) {
try (DatagramSocket socket = new DatagramSocket(0, InetAddress.getByName("127.0.0.1"))) { try (DatagramSocket socket = new DatagramSocket(0, InetAddress.getByName("127.0.0.1"))) {
socket.setReuseAddress(true);
return socket.getLocalPort(); return socket.getLocalPort();
} catch (Exception ex) { } catch (Exception ex) {
throw new RuntimeException("Failed to get a UDP server socket point"); throw new RuntimeException("Failed to get a UDP server socket point");