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

feat: readyz polling for startup #56

Merged
merged 7 commits into from
Mar 29, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class KubeAPIServer implements UnexpectedProcessStopHandler {

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

public static final int STARTUP_TIMEOUT = 15_000;
public static final int STARTUP_TIMEOUT = 10_000;

private final KubeAPIServerConfig config;
private final BinaryManager binaryManager;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,45 @@

import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.net.ssl.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.javaoperatorsdk.jenvtest.*;
import io.javaoperatorsdk.jenvtest.binary.BinaryManager;

import static io.javaoperatorsdk.jenvtest.KubeAPIServer.STARTUP_TIMEOUT;

public class KubeAPIServerProcess {

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

private final CertManager certManager;
private final BinaryManager binaryManager;
private final KubeAPIServerConfig config;
private volatile Process apiServerProcess;
private volatile boolean stopped = false;
private final UnexpectedProcessStopHandler processStopHandler;
private int apiServerPort;

public KubeAPIServerProcess(CertManager certManager, BinaryManager binaryManager,
UnexpectedProcessStopHandler processStopHandler,
Expand All @@ -42,7 +58,7 @@ public int startApiServer(int etcdPort) {
throw new JenvtestException(
"Missing binary for API Server on path: " + apiServerBinary.getAbsolutePath());
}
var apiServerPort = Utils.findFreePort();
apiServerPort = Utils.findFreePort();
var command = createCommand(apiServerBinary, apiServerPort, etcdPort);
apiServerProcess = new ProcessBuilder(command)
.start();
Expand Down Expand Up @@ -85,27 +101,29 @@ private List<String> createCommand(File apiServerBinary, int apiServerPort, int

public void waitUntilDefaultNamespaceCreated() {
try {
AtomicBoolean started = new AtomicBoolean(false);
var proc = new ProcessBuilder(binaryManager.binaries().getKubectl().getPath(), "get", "ns",
"--watch").start();
var procWaiter = new Thread(() -> {
log.debug("Starting proc waiter thread.");
try (Scanner sc = new Scanner(proc.getInputStream())) {
while (sc.hasNextLine()) {
String line = sc.nextLine();
log.debug("kubectl ns watch: {}", line);
if (line.contains("default")) {
started.set(true);
return;
}
}
var client = getHttpClient();
var request = getHttpRequest();
var startedAt = LocalTime.now();
while (true) {
if (ready(client, request)) {
return;
}
});
procWaiter.start();
procWaiter.join(KubeAPIServer.STARTUP_TIMEOUT);
if (!started.get()) {
throw new JenvtestException("API Server did not start properly");
if (LocalTime.now().isAfter(startedAt.plus(STARTUP_TIMEOUT, ChronoUnit.MILLIS))) {
throw new JenvtestException("API Server did not start properly");
}
Thread.sleep(POLLING_INTERVAL);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new JenvtestException(e);
}
}

private boolean ready(HttpClient client, HttpRequest request) {
try {
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
log.trace("Ready Response message:{} code: {}", response.body(), response.statusCode());
return response.statusCode() == 200;
} catch (IOException e) {
throw new JenvtestException(e);
} catch (InterruptedException e) {
Expand All @@ -114,6 +132,69 @@ public void waitUntilDefaultNamespaceCreated() {
}
}

private HttpRequest getHttpRequest() {
try {
return HttpRequest.newBuilder()
.uri(new URI("https://127.0.0.1:" + apiServerPort + "/readyz"))
.GET()
.build();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}

private static HttpClient getHttpClient() {
try {
var sslContext = SSLContext.getInstance("TLS");
sslContext.init(
null,
new TrustManager[] {
new X509ExtendedTrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,

Check failure

Code scanning / SonarCloud

Server certificates should be verified during SSL/TLS connections

<!--SONAR_ISSUE_KEY:AYcs9LV_zKUzN5JdWgIw-->Enable server certificate validation on this SSL/TLS connection. <p>See more on <a href="https://sonarcloud.io/project/issues?id=java-operator-sdk_jenvtest&issues=AYcs9LV_zKUzN5JdWgIw&open=AYcs9LV_zKUzN5JdWgIw&pullRequest=56">SonarCloud</a></p>
Socket socket) throws CertificateException {

}

public X509Certificate[] getAcceptedIssuers() {
return null;
}

public void checkClientTrusted(

Check failure

Code scanning / SonarCloud

Server certificates should be verified during SSL/TLS connections

<!--SONAR_ISSUE_KEY:AYcs9LV_zKUzN5JdWgIy-->Enable server certificate validation on this SSL/TLS connection. <p>See more on <a href="https://sonarcloud.io/project/issues?id=java-operator-sdk_jenvtest&issues=AYcs9LV_zKUzN5JdWgIy&open=AYcs9LV_zKUzN5JdWgIy&pullRequest=56">SonarCloud</a></p>
final X509Certificate[] a_certificates,
final String a_auth_type) {}

public void checkServerTrusted(

Check failure

Code scanning / SonarCloud

Server certificates should be verified during SSL/TLS connections

<!--SONAR_ISSUE_KEY:AYcs9LV_zKUzN5JdWgIz-->Enable server certificate validation on this SSL/TLS connection. <p>See more on <a href="https://sonarcloud.io/project/issues?id=java-operator-sdk_jenvtest&issues=AYcs9LV_zKUzN5JdWgIz&open=AYcs9LV_zKUzN5JdWgIz&pullRequest=56">SonarCloud</a></p>
final X509Certificate[] a_certificates,
final String a_auth_type) {}


public void checkServerTrusted(

Check failure

Code scanning / SonarCloud

Server certificates should be verified during SSL/TLS connections

<!--SONAR_ISSUE_KEY:AYcs9LV_zKUzN5JdWgI0-->Enable server certificate validation on this SSL/TLS connection. <p>See more on <a href="https://sonarcloud.io/project/issues?id=java-operator-sdk_jenvtest&issues=AYcs9LV_zKUzN5JdWgI0&open=AYcs9LV_zKUzN5JdWgI0&pullRequest=56">SonarCloud</a></p>
final X509Certificate[] a_certificates,
final String a_auth_type,
final Socket a_socket) {}

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType,

Check failure

Code scanning / SonarCloud

Server certificates should be verified during SSL/TLS connections

<!--SONAR_ISSUE_KEY:AYcs9LV_zKUzN5JdWgI1-->Enable server certificate validation on this SSL/TLS connection. <p>See more on <a href="https://sonarcloud.io/project/issues?id=java-operator-sdk_jenvtest&issues=AYcs9LV_zKUzN5JdWgI1&open=AYcs9LV_zKUzN5JdWgI1&pullRequest=56">SonarCloud</a></p>
SSLEngine engine) throws CertificateException {

}

public void checkServerTrusted(

Check failure

Code scanning / SonarCloud

Server certificates should be verified during SSL/TLS connections

<!--SONAR_ISSUE_KEY:AYcs9LV_zKUzN5JdWgI2-->Enable server certificate validation on this SSL/TLS connection. <p>See more on <a href="https://sonarcloud.io/project/issues?id=java-operator-sdk_jenvtest&issues=AYcs9LV_zKUzN5JdWgI2&open=AYcs9LV_zKUzN5JdWgI2&pullRequest=56">SonarCloud</a></p>
final X509Certificate[] a_certificates,
final String a_auth_type,
final SSLEngine a_engine) {}
}
},
null);
return HttpClient.newBuilder()
.sslContext(sslContext)
.build();
} catch (NoSuchAlgorithmException | KeyManagementException e) {
throw new JenvtestException(e);
}
}

public void stopApiServer() {
if (stopped) {
return;
Expand Down