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

Commit b7d1e9a

Browse files
committed
refactor: extract process handling
1 parent 9e6d39f commit b7d1e9a

File tree

4 files changed

+182
-129
lines changed

4 files changed

+182
-129
lines changed
Lines changed: 11 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package com.csviri.kubeapi;
22

3-
import org.apache.commons.io.FileUtils;
43
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
65

76
import java.io.*;
8-
import java.util.Scanner;
9-
import java.util.concurrent.atomic.AtomicBoolean;
107

118
public class APIServer {
129

@@ -18,9 +15,8 @@ public class APIServer {
1815
private final BinaryManager binaryManager;
1916
private final CertManager certManager;
2017
private final KubeConfigManager kubeConfigManager;
21-
private Process etcdProcess;
22-
private volatile Process apiServerProcess;
23-
private volatile boolean stopped = false;
18+
private final EtcdProcessManager etcdProcessManager;
19+
private final APIServerProcessManager apiServerProcessManager;
2420

2521
public APIServer() {
2622
this(new APIServerConfig());
@@ -31,25 +27,26 @@ public APIServer(APIServerConfig config) {
3127
this.binaryManager = new BinaryManager(config.getJenvtestDirectory(),config.getApiServerVersion());
3228
this.certManager = new CertManager(config.getJenvtestDirectory());
3329
this.kubeConfigManager = new KubeConfigManager(certManager,binaryManager);
30+
this.etcdProcessManager = new EtcdProcessManager(binaryManager,config);
31+
this.apiServerProcessManager = new APIServerProcessManager(certManager,binaryManager,config);
3432
}
3533

3634
public void start() {
3735
log.debug("Stating API Server. Using jenvtest dir: {}", config.getJenvtestDirectory());
3836
prepareLogDirectory();
39-
cleanEtcdData();
40-
startEtcd();
41-
startApiServer();
37+
etcdProcessManager.cleanEtcdData();
38+
etcdProcessManager.startEtcd();
39+
apiServerProcessManager.startApiServer();
4240
kubeConfigManager.updateKubeConfig();
43-
waitUntilDefaultNamespaceCreated();
41+
apiServerProcessManager.waitUntilDefaultNamespaceCreated();
4442
log.info("API Server ready to use");
4543
}
4644

4745
public void stop() {
48-
stopped = true;
49-
stopApiServer();
50-
stopEtcd();
46+
apiServerProcessManager.stopApiServer();
47+
etcdProcessManager.stopEtcd();
5148
kubeConfigManager.cleanupFromKubeConfig();
52-
cleanEtcdData();
49+
etcdProcessManager.cleanEtcdData();
5350
log.debug("Fully stopped.");
5451
}
5552

@@ -62,117 +59,4 @@ private void prepareLogDirectory() {
6259
}
6360
}
6461
}
65-
66-
67-
private void stopApiServer() {
68-
if (apiServerProcess != null) {
69-
apiServerProcess.destroyForcibly();
70-
}
71-
log.debug("API Server stopped");
72-
}
73-
74-
private void cleanEtcdData() {
75-
try {
76-
FileUtils.deleteDirectory(new File("default.etcd"));
77-
} catch (IOException e) {
78-
throw new KubeApiException(e);
79-
}
80-
}
81-
82-
private void stopEtcd() {
83-
if (etcdProcess != null) {
84-
etcdProcess.destroy();
85-
}
86-
log.debug("etcd stopped");
87-
}
88-
89-
private void waitUntilDefaultNamespaceCreated() {
90-
try {
91-
AtomicBoolean started = new AtomicBoolean(false);
92-
var proc = new ProcessBuilder(binaryManager.binaries().getKubectl().getPath(),"get","ns","--watch").start();
93-
var procWaiter = new Thread(() -> {
94-
try(Scanner sc = new Scanner(proc.getInputStream())){
95-
while (sc.hasNextLine()) {
96-
String line = sc.nextLine();
97-
if (line.contains("default")) {
98-
started.set(true);
99-
return;
100-
}
101-
}
102-
}
103-
});
104-
procWaiter.start();
105-
procWaiter.join(APIServer.STARTUP_TIMEOUT);
106-
if (!started.get()) {
107-
throw new KubeApiException("API Server did not start properly. Check the log files.");
108-
}
109-
} catch (IOException e) {
110-
throw new KubeApiException(e);
111-
} catch (InterruptedException e) {
112-
Thread.currentThread().interrupt();
113-
throw new KubeApiException(e);
114-
}
115-
}
116-
117-
private void startEtcd() {
118-
var etcdBinary = binaryManager.binaries().getEtcd();
119-
try {
120-
if (!etcdBinary.exists()) {
121-
throw new KubeApiException("Missing binary for etcd on path: " + etcdBinary.getAbsolutePath());
122-
}
123-
var logsFile = new File(config.logDirectory(), "etcd.logs");
124-
125-
etcdProcess = new ProcessBuilder(etcdBinary.getAbsolutePath(),
126-
"--listen-client-urls=http://0.0.0.0:2379",
127-
"--advertise-client-urls=http://0.0.0.0:2379")
128-
// todo log to a different logger on debug level
129-
.redirectOutput(logsFile)
130-
.redirectError(logsFile)
131-
.start();
132-
etcdProcess.onExit().thenApply(p-> {
133-
if (!stopped) {
134-
throw new KubeApiException("Etcd stopped unexpectedly");
135-
}
136-
return null;
137-
});
138-
log.debug("etcd started");
139-
} catch (IOException e) {
140-
throw new KubeApiException(e);
141-
}
142-
}
143-
144-
private void startApiServer() {
145-
certManager.ensureAPIServerCertificates();
146-
var apiServerBinary = binaryManager.binaries().getApiServer();
147-
try {
148-
if (!apiServerBinary.exists()) {
149-
throw new KubeApiException("Missing binary for API Server on path: " + apiServerBinary.getAbsolutePath());
150-
}
151-
152-
apiServerProcess = new ProcessBuilder(apiServerBinary.getAbsolutePath(),
153-
"--cert-dir", config.getJenvtestDirectory(),
154-
"--etcd-servers", "http://0.0.0.0:2379",
155-
"--authorization-mode", "RBAC",
156-
"--service-account-issuer", "https://localhost",
157-
"--service-account-signing-key-file", certManager.getAPIServerKeyPath(),
158-
"--service-account-signing-key-file", certManager.getAPIServerKeyPath(),
159-
"--service-account-key-file", certManager.getAPIServerKeyPath(),
160-
"--service-account-issuer", certManager.getAPIServerCertPath(),
161-
"--disable-admission-plugins", "ServiceAccount",
162-
"--client-ca-file", certManager.getClientCertPath(),
163-
"--service-cluster-ip-range", "10.0.0.0/24",
164-
"--allow-privileged"
165-
)
166-
.start();
167-
apiServerProcess.onExit().thenApply(p-> {
168-
if (!stopped) {
169-
throw new KubeApiException("APIServer stopped unexpectedly.");
170-
}
171-
return null;
172-
});
173-
log.debug("API Server started");
174-
} catch (IOException e) {
175-
throw new RuntimeException(e);
176-
}
177-
}
17862
}

src/main/java/com/csviri/kubeapi/APIServerConfig.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44

55
public class APIServerConfig {
66

7+
public static final String CONFIG_ROOT_ENV_VAR = "JENVTEST_DIR";
78
public static final String DIRECTORY_NAME = ".jenvtest";
89

910
/**
10-
* Set home directory of the project. Default is ~/.jenvtest
11+
* Set directory where binaries and other assets are present. Default is ~/.jenvtest.
1112
**/
1213
private String jenvtestDir;
1314

@@ -17,7 +18,12 @@ public class APIServerConfig {
1718
private String apiServerVersion;
1819

1920
public APIServerConfig() {
20-
this.jenvtestDir = new File(System.getProperty("user.home"), DIRECTORY_NAME).getPath();
21+
var jenvtestDirFromEnvVar = System.getenv(CONFIG_ROOT_ENV_VAR);
22+
if (jenvtestDirFromEnvVar != null) {
23+
this.jenvtestDir = jenvtestDirFromEnvVar;
24+
} else {
25+
this.jenvtestDir = new File(System.getProperty("user.home"), DIRECTORY_NAME).getPath();
26+
}
2127
}
2228

2329
public String getJenvtestDirectory() {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package com.csviri.kubeapi;
2+
3+
import org.slf4j.Logger;
4+
import org.slf4j.LoggerFactory;
5+
6+
import java.io.IOException;
7+
import java.util.Scanner;
8+
import java.util.concurrent.atomic.AtomicBoolean;
9+
10+
public class APIServerProcessManager {
11+
12+
private static final Logger log = LoggerFactory.getLogger(APIServerProcessManager.class);
13+
14+
private final CertManager certManager;
15+
private final BinaryManager binaryManager;
16+
private final APIServerConfig config;
17+
private volatile Process apiServerProcess;
18+
private volatile boolean stopped = false;
19+
20+
public APIServerProcessManager(CertManager certManager, BinaryManager binaryManager,APIServerConfig config) {
21+
this.certManager = certManager;
22+
this.binaryManager = binaryManager;
23+
this.config = config;
24+
}
25+
26+
27+
public void startApiServer() {
28+
certManager.ensureAPIServerCertificates();
29+
var apiServerBinary = binaryManager.binaries().getApiServer();
30+
try {
31+
if (!apiServerBinary.exists()) {
32+
throw new KubeApiException("Missing binary for API Server on path: " + apiServerBinary.getAbsolutePath());
33+
}
34+
35+
apiServerProcess = new ProcessBuilder(apiServerBinary.getAbsolutePath(),
36+
"--cert-dir", config.getJenvtestDirectory(),
37+
"--etcd-servers", "http://0.0.0.0:2379",
38+
"--authorization-mode", "RBAC",
39+
"--service-account-issuer", "https://localhost",
40+
"--service-account-signing-key-file", certManager.getAPIServerKeyPath(),
41+
"--service-account-signing-key-file", certManager.getAPIServerKeyPath(),
42+
"--service-account-key-file", certManager.getAPIServerKeyPath(),
43+
"--service-account-issuer", certManager.getAPIServerCertPath(),
44+
"--disable-admission-plugins", "ServiceAccount",
45+
"--client-ca-file", certManager.getClientCertPath(),
46+
"--service-cluster-ip-range", "10.0.0.0/24",
47+
"--allow-privileged"
48+
)
49+
.start();
50+
apiServerProcess.onExit().thenApply(p-> {
51+
if (!stopped) {
52+
throw new KubeApiException("APIServer stopped unexpectedly.");
53+
}
54+
return null;
55+
});
56+
log.debug("API Server started");
57+
} catch (IOException e) {
58+
throw new RuntimeException(e);
59+
}
60+
}
61+
62+
public void waitUntilDefaultNamespaceCreated() {
63+
try {
64+
AtomicBoolean started = new AtomicBoolean(false);
65+
var proc = new ProcessBuilder(binaryManager.binaries().getKubectl().getPath(),"get","ns","--watch").start();
66+
var procWaiter = new Thread(() -> {
67+
try(Scanner sc = new Scanner(proc.getInputStream())){
68+
while (sc.hasNextLine()) {
69+
String line = sc.nextLine();
70+
if (line.contains("default")) {
71+
started.set(true);
72+
return;
73+
}
74+
}
75+
}
76+
});
77+
procWaiter.start();
78+
procWaiter.join(APIServer.STARTUP_TIMEOUT);
79+
if (!started.get()) {
80+
throw new KubeApiException("API Server did not start properly. Check the log files.");
81+
}
82+
} catch (IOException e) {
83+
throw new KubeApiException(e);
84+
} catch (InterruptedException e) {
85+
Thread.currentThread().interrupt();
86+
throw new KubeApiException(e);
87+
}
88+
}
89+
90+
public void stopApiServer() {
91+
stopped = true;
92+
if (apiServerProcess != null) {
93+
apiServerProcess.destroyForcibly();
94+
}
95+
log.debug("API Server stopped");
96+
}
97+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package com.csviri.kubeapi;
2+
3+
import org.apache.commons.io.FileUtils;
4+
import org.slf4j.Logger;
5+
import org.slf4j.LoggerFactory;
6+
7+
import java.io.File;
8+
import java.io.IOException;
9+
10+
public class EtcdProcessManager {
11+
12+
private static final Logger log = LoggerFactory.getLogger(EtcdProcessManager.class);
13+
14+
private final BinaryManager binaryManager;
15+
private final APIServerConfig config;
16+
private volatile Process etcdProcess;
17+
private volatile boolean stopped = false;
18+
19+
public EtcdProcessManager(BinaryManager binaryManager, APIServerConfig config) {
20+
this.binaryManager = binaryManager;
21+
this.config = config;
22+
}
23+
24+
public void startEtcd() {
25+
var etcdBinary = binaryManager.binaries().getEtcd();
26+
try {
27+
if (!etcdBinary.exists()) {
28+
throw new KubeApiException("Missing binary for etcd on path: " + etcdBinary.getAbsolutePath());
29+
}
30+
var logsFile = new File(config.logDirectory(), "etcd.logs");
31+
32+
etcdProcess = new ProcessBuilder(etcdBinary.getAbsolutePath(),
33+
"--listen-client-urls=http://0.0.0.0:2379",
34+
"--advertise-client-urls=http://0.0.0.0:2379")
35+
// todo log to a different logger on debug level
36+
.redirectOutput(logsFile)
37+
.redirectError(logsFile)
38+
.start();
39+
etcdProcess.onExit().thenApply(p-> {
40+
if (!stopped) {
41+
throw new KubeApiException("Etcd stopped unexpectedly");
42+
}
43+
return null;
44+
});
45+
log.debug("etcd started");
46+
} catch (IOException e) {
47+
throw new KubeApiException(e);
48+
}
49+
}
50+
51+
public void cleanEtcdData() {
52+
try {
53+
FileUtils.deleteDirectory(new File("default.etcd"));
54+
} catch (IOException e) {
55+
throw new KubeApiException(e);
56+
}
57+
}
58+
59+
public void stopEtcd() {
60+
stopped = true;
61+
if (etcdProcess != null) {
62+
etcdProcess.destroy();
63+
}
64+
log.debug("etcd stopped");
65+
}
66+
}

0 commit comments

Comments
 (0)