22
33import java .io .File ;
44import 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 ;
518import java .util .ArrayList ;
619import java .util .List ;
7- import java . util . Scanner ;
8- import java . util . concurrent . atomic . AtomicBoolean ;
20+
21+ import javax . net . ssl .* ;
922
1023import org .slf4j .Logger ;
1124import org .slf4j .LoggerFactory ;
1225
1326import io .javaoperatorsdk .jenvtest .*;
1427import io .javaoperatorsdk .jenvtest .binary .BinaryManager ;
1528
29+ import static io .javaoperatorsdk .jenvtest .KubeAPIServer .STARTUP_TIMEOUT ;
30+
1631public 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