Skip to content
This repository was archived by the owner on Apr 10, 2024. It is now read-only.

Commit f72b7a1

Browse files
authored
feat: readyz polling for startup (#56)
1 parent da90d33 commit f72b7a1

File tree

2 files changed

+109
-23
lines changed

2 files changed

+109
-23
lines changed

core/src/main/java/io/javaoperatorsdk/jenvtest/KubeAPIServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class KubeAPIServer implements UnexpectedProcessStopHandler {
1212

1313
private static final Logger log = LoggerFactory.getLogger(KubeAPIServer.class);
1414

15-
public static final int STARTUP_TIMEOUT = 15_000;
15+
public static final int STARTUP_TIMEOUT = 10_000;
1616

1717
private final KubeAPIServerConfig config;
1818
private final BinaryManager binaryManager;

core/src/main/java/io/javaoperatorsdk/jenvtest/process/KubeAPIServerProcess.java

Lines changed: 108 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,46 @@
22

33
import java.io.File;
44
import java.io.IOException;
5+
import java.net.ConnectException;
6+
import java.net.Socket;
7+
import java.net.URI;
8+
import java.net.URISyntaxException;
9+
import java.net.http.HttpClient;
10+
import java.net.http.HttpRequest;
11+
import java.net.http.HttpResponse;
12+
import java.security.KeyManagementException;
13+
import java.security.NoSuchAlgorithmException;
14+
import java.security.cert.CertificateException;
15+
import java.security.cert.X509Certificate;
16+
import java.time.LocalTime;
17+
import java.time.temporal.ChronoUnit;
518
import java.util.ArrayList;
619
import java.util.List;
7-
import java.util.Scanner;
8-
import java.util.concurrent.atomic.AtomicBoolean;
20+
21+
import javax.net.ssl.*;
922

1023
import org.slf4j.Logger;
1124
import org.slf4j.LoggerFactory;
1225

1326
import io.javaoperatorsdk.jenvtest.*;
1427
import io.javaoperatorsdk.jenvtest.binary.BinaryManager;
1528

29+
import static io.javaoperatorsdk.jenvtest.KubeAPIServer.STARTUP_TIMEOUT;
30+
1631
public class KubeAPIServerProcess {
1732

1833
private static final Logger log = LoggerFactory.getLogger(KubeAPIServerProcess.class);
1934
private static final Logger apiLog = LoggerFactory.getLogger(KubeAPIServerProcess.class
2035
.getName() + ".APIServerProcessLogs");
36+
public static final int POLLING_INTERVAL = 150;
2137

2238
private final CertManager certManager;
2339
private final BinaryManager binaryManager;
2440
private final KubeAPIServerConfig config;
2541
private volatile Process apiServerProcess;
2642
private volatile boolean stopped = false;
2743
private final UnexpectedProcessStopHandler processStopHandler;
44+
private int apiServerPort;
2845

2946
public KubeAPIServerProcess(CertManager certManager, BinaryManager binaryManager,
3047
UnexpectedProcessStopHandler processStopHandler,
@@ -42,7 +59,7 @@ public int startApiServer(int etcdPort) {
4259
throw new JenvtestException(
4360
"Missing binary for API Server on path: " + apiServerBinary.getAbsolutePath());
4461
}
45-
var apiServerPort = Utils.findFreePort();
62+
apiServerPort = Utils.findFreePort();
4663
var command = createCommand(apiServerBinary, apiServerPort, etcdPort);
4764
apiServerProcess = new ProcessBuilder(command)
4865
.start();
@@ -85,27 +102,33 @@ private List<String> createCommand(File apiServerBinary, int apiServerPort, int
85102

86103
public void waitUntilDefaultNamespaceCreated() {
87104
try {
88-
AtomicBoolean started = new AtomicBoolean(false);
89-
var proc = new ProcessBuilder(binaryManager.binaries().getKubectl().getPath(), "get", "ns",
90-
"--watch").start();
91-
var procWaiter = new Thread(() -> {
92-
log.debug("Starting proc waiter thread.");
93-
try (Scanner sc = new Scanner(proc.getInputStream())) {
94-
while (sc.hasNextLine()) {
95-
String line = sc.nextLine();
96-
log.debug("kubectl ns watch: {}", line);
97-
if (line.contains("default")) {
98-
started.set(true);
99-
return;
100-
}
101-
}
105+
var client = getHttpClient();
106+
var request = getHttpRequest();
107+
var startedAt = LocalTime.now();
108+
while (true) {
109+
if (ready(client, request)) {
110+
return;
102111
}
103-
});
104-
procWaiter.start();
105-
procWaiter.join(KubeAPIServer.STARTUP_TIMEOUT);
106-
if (!started.get()) {
107-
throw new JenvtestException("API Server did not start properly");
112+
if (LocalTime.now().isAfter(startedAt.plus(STARTUP_TIMEOUT, ChronoUnit.MILLIS))) {
113+
throw new JenvtestException("API Server did not start properly");
114+
}
115+
Thread.sleep(POLLING_INTERVAL);
108116
}
117+
} catch (InterruptedException e) {
118+
Thread.currentThread().interrupt();
119+
throw new JenvtestException(e);
120+
}
121+
}
122+
123+
private boolean ready(HttpClient client, HttpRequest request) {
124+
try {
125+
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
126+
log.trace("Ready Response message:{} code: {}", response.body(), response.statusCode());
127+
return response.statusCode() == 200;
128+
} catch (ConnectException e) {
129+
// still want to retry
130+
log.warn("Cannot connect to the server", e);
131+
return false;
109132
} catch (IOException e) {
110133
throw new JenvtestException(e);
111134
} catch (InterruptedException e) {
@@ -114,6 +137,69 @@ public void waitUntilDefaultNamespaceCreated() {
114137
}
115138
}
116139

140+
private HttpRequest getHttpRequest() {
141+
try {
142+
return HttpRequest.newBuilder()
143+
.uri(new URI("https://127.0.0.1:" + apiServerPort + "/readyz"))
144+
.GET()
145+
.build();
146+
} catch (URISyntaxException e) {
147+
throw new RuntimeException(e);
148+
}
149+
}
150+
151+
private static HttpClient getHttpClient() {
152+
try {
153+
var sslContext = SSLContext.getInstance("TLS");
154+
sslContext.init(
155+
null,
156+
new TrustManager[] {
157+
new X509ExtendedTrustManager() {
158+
@Override
159+
public void checkClientTrusted(X509Certificate[] chain, String authType,
160+
Socket socket) throws CertificateException {
161+
162+
}
163+
164+
public X509Certificate[] getAcceptedIssuers() {
165+
return null;
166+
}
167+
168+
public void checkClientTrusted(
169+
final X509Certificate[] a_certificates,
170+
final String a_auth_type) {}
171+
172+
public void checkServerTrusted(
173+
final X509Certificate[] a_certificates,
174+
final String a_auth_type) {}
175+
176+
177+
public void checkServerTrusted(
178+
final X509Certificate[] a_certificates,
179+
final String a_auth_type,
180+
final Socket a_socket) {}
181+
182+
@Override
183+
public void checkClientTrusted(X509Certificate[] chain, String authType,
184+
SSLEngine engine) throws CertificateException {
185+
186+
}
187+
188+
public void checkServerTrusted(
189+
final X509Certificate[] a_certificates,
190+
final String a_auth_type,
191+
final SSLEngine a_engine) {}
192+
}
193+
},
194+
null);
195+
return HttpClient.newBuilder()
196+
.sslContext(sslContext)
197+
.build();
198+
} catch (NoSuchAlgorithmException | KeyManagementException e) {
199+
throw new JenvtestException(e);
200+
}
201+
}
202+
117203
public void stopApiServer() {
118204
if (stopped) {
119205
return;

0 commit comments

Comments
 (0)