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

Commit 3abef12

Browse files
committed
feat: envtest setup compatibility
1 parent 5be84e0 commit 3abef12

File tree

7 files changed

+150
-34
lines changed

7 files changed

+150
-34
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
# jenvtest
22

3-
Jenvtest is similar to envtest in controller runtime to support unit testing with API Server, just for Java:
3+
Jenvtest is similar to envtest, to support unit testing with API Server - just for Java:
44
https://book.kubebuilder.io/reference/envtest.html
55

66
Project is in early phases, heading towards mvp release.
77

8+
## Usage
9+
10+

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

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
public class APIServer {
1212

1313
private static final Logger log = LoggerFactory.getLogger(APIServer.class);
14+
1415
public static final int STARTUP_TIMEOUT = 10_000;
1516

1617
private final APIServerConfig config;
@@ -27,9 +28,9 @@ public APIServer() {
2728

2829
public APIServer(APIServerConfig config) {
2930
this.config = config;
30-
this.binaryManager = new BinaryManager(config.getJenvtestDirectory());
31+
this.binaryManager = new BinaryManager(config.getJenvtestDirectory(),config.getApiServerVersion());
3132
this.certManager = new CertManager(config.getJenvtestDirectory());
32-
this.kubeConfigManager = new KubeConfigManager(certManager);
33+
this.kubeConfigManager = new KubeConfigManager(certManager,binaryManager);
3334
}
3435

3536
public void start() {
@@ -39,7 +40,7 @@ public void start() {
3940
startEtcd();
4041
startApiServer();
4142
kubeConfigManager.updateKubeConfig();
42-
waitUntilDefaultNamespaceCreatedWithK();
43+
waitUntilDefaultNamespaceCreated();
4344
log.info("API Server ready to use");
4445
}
4546

@@ -85,10 +86,10 @@ private void stopEtcd() {
8586
log.debug("etcd stopped");
8687
}
8788

88-
private void waitUntilDefaultNamespaceCreatedWithK() {
89+
private void waitUntilDefaultNamespaceCreated() {
8990
try {
9091
AtomicBoolean started = new AtomicBoolean(false);
91-
var proc = new ProcessBuilder("kubectl","get","ns","--watch").start();
92+
var proc = new ProcessBuilder(binaryManager.binaries().getKubectl().getPath(),"get","ns","--watch").start();
9293
var procWaiter = new Thread(() -> {
9394
try(Scanner sc = new Scanner(proc.getInputStream())){
9495
while (sc.hasNextLine()) {
@@ -113,7 +114,6 @@ private void waitUntilDefaultNamespaceCreatedWithK() {
113114
}
114115
}
115116

116-
// todo detect if process not started up correctly
117117
private void startEtcd() {
118118
var etcdBinary = binaryManager.binaries().getEtcd();
119119
try {
@@ -122,7 +122,6 @@ private void startEtcd() {
122122
}
123123
var logsFile = new File(config.logDirectory(), "etcd.logs");
124124

125-
// todo config ports
126125
etcdProcess = new ProcessBuilder(etcdBinary.getAbsolutePath(),
127126
"--listen-client-urls=http://0.0.0.0:2379",
128127
"--advertise-client-urls=http://0.0.0.0:2379")

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ public class APIServerConfig {
77
public static final String DIRECTORY_NAME = ".jenvtest";
88

99
private String jenvtestDir;
10+
// todo support wildcard 1.26.*
11+
/**
12+
* Sample: 1.26.1, 1.25.0
13+
*/
14+
private String apiServerVersion;
1015

1116
public APIServerConfig() {
1217
this.jenvtestDir = System.getProperty("user.home") + File.separator + DIRECTORY_NAME;
@@ -21,6 +26,15 @@ public APIServerConfig setJenvtestDir(String jenvtestDir) {
2126
return this;
2227
}
2328

29+
public String getApiServerVersion() {
30+
return apiServerVersion;
31+
}
32+
33+
public APIServerConfig setApiServerVersion(String apiServerVersion) {
34+
this.apiServerVersion = apiServerVersion;
35+
return this;
36+
}
37+
2438
public String logDirectory() {
2539
return new File(jenvtestDir,"logs").getPath();
2640
}
Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,57 @@
11
package com.csviri.kubeapi;
22

33
import java.io.File;
4+
import java.util.List;
5+
import java.util.stream.Collectors;
6+
7+
import static java.util.List.of;
48

59
public class BinaryManager {
6-
7-
public static final String DEFAULT_VERSION_1_26_1 = "v1.26.2";
8-
public static final String DEFAULT_ETD_VERSION = "v3.4.24";
10+
911
public static final String ETCD_BINARY_NAME = "etcd";
1012
public static final String API_SERVER_BINARY_NAME = "kube-apiserver";
1113
public static final String KUBECTL_BINARY_NAME = "kubectl";
14+
public static final String BINARY_LIST_DIR = "k8s";
1215

13-
// todo configurable
14-
//https://dl.k8s.io/v1.26.1/bin/linux/amd64/kube-apiserver
15-
private String version = DEFAULT_VERSION_1_26_1;
16+
private Binaries binaries;
1617

1718
private String jenvtestDir;
19+
private String apiServerVersion;
1820

19-
public BinaryManager(String jenvtestDir) {
21+
public BinaryManager(String jenvtestDir, String apiServerVersion) {
2022
this.jenvtestDir = jenvtestDir;
23+
this.apiServerVersion = apiServerVersion;
24+
init();
2125
}
2226

23-
public void downloadBinariesIfNotPresent() {
27+
private void init() {
28+
File binaryDir = targetBinaryDir();
2429

30+
this.binaries = new Binaries(new File(binaryDir, ETCD_BINARY_NAME),
31+
new File(binaryDir, API_SERVER_BINARY_NAME),
32+
new File(binaryDir, KUBECTL_BINARY_NAME));
33+
if (!binaries.getApiServer().exists()) {
34+
throw new KubeApiException("API Server binary not found at path:" + binaries.getApiServer().getPath());
35+
}
36+
if (!binaries.getKubectl().exists()) {
37+
throw new KubeApiException("Kubectl binary not found at path:" + binaries.getKubectl().getPath());
38+
}
39+
if (!binaries.getEtcd().exists()) {
40+
throw new KubeApiException("Etcd binary not found at path:" + binaries.getEtcd().getPath());
41+
}
2542
}
2643

27-
public ApiBinaries binaries() {
28-
return new ApiBinaries(new File(jenvtestDir, ETCD_BINARY_NAME),
29-
new File(jenvtestDir, API_SERVER_BINARY_NAME),
30-
new File(jenvtestDir, KUBECTL_BINARY_NAME));
44+
public Binaries binaries() {
45+
return binaries;
46+
3147
}
3248

33-
public static class ApiBinaries {
49+
public static class Binaries {
3450
private final File etcd;
3551
private final File apiServer;
3652
private final File kubectl;
3753

38-
public ApiBinaries(File etcd, File apiServer, File kubectl) {
54+
public Binaries(File etcd, File apiServer, File kubectl) {
3955
this.etcd = etcd;
4056
this.apiServer = apiServer;
4157
this.kubectl = kubectl;
@@ -53,4 +69,22 @@ public File getKubectl() {
5369
return kubectl;
5470
}
5571
}
72+
73+
private File targetBinaryDir() {
74+
String os = System.getProperty("os.name");
75+
String arch = System.getProperty("os.arch");
76+
String platformSuffix = ("-" + os + "-" + arch).toLowerCase();
77+
if (apiServerVersion != null) {
78+
return new File(jenvtestDir, BINARY_LIST_DIR + File.separator + apiServerVersion + platformSuffix);
79+
}
80+
File binariesListDir = new File(jenvtestDir, BINARY_LIST_DIR);
81+
var dirVersionList = List.of(binariesListDir.list((dir, name) -> name.endsWith(platformSuffix)))
82+
.stream().map(s -> s.substring(0,s.indexOf(platformSuffix)))
83+
.collect(Collectors.toList());
84+
85+
String latest = SemverUtil.getLatestVersion(dirVersionList) + platformSuffix;
86+
return new File(binariesListDir, latest);
87+
}
88+
89+
5690
}

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

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,56 @@
44
import org.slf4j.LoggerFactory;
55

66
import java.io.IOException;
7+
import java.util.ArrayList;
8+
import java.util.List;
79

810
public class KubeConfigManager {
911

1012
private static final Logger log = LoggerFactory.getLogger(KubeConfigManager.class);
13+
public static final String JENVTEST = "jenvtest";
14+
1115
private CertManager certManager;
16+
private BinaryManager binaryManager;
1217

13-
public KubeConfigManager(CertManager certManager) {
18+
public KubeConfigManager(CertManager certManager, BinaryManager binaryManager) {
1419
this.certManager = certManager;
20+
this.binaryManager = binaryManager;
1521
}
1622

1723
public void updateKubeConfig() {
1824
log.debug("Updating kubeconfig");
19-
execAndWait("kubectl", "config", "set-cluster", "jenvtest", "--server=https://127.0.0.1:6443",
25+
execWithKubectlConfigAndWait("set-cluster", JENVTEST, "--server=https://127.0.0.1:6443",
2026
"--certificate-authority=" + certManager.getAPIServerCertPath());
21-
execAndWait("kubectl", "config", "set-credentials", "jenvtest",
27+
execWithKubectlConfigAndWait( "set-credentials", JENVTEST,
2228
"--client-certificate=" + certManager.getClientCertPath(), "--client-key=" + certManager.getClientKeyPath());
23-
execAndWait("kubectl", "config", "set-context", "jenvtest", "--cluster=jenvtest",
29+
execWithKubectlConfigAndWait("set-context", JENVTEST, "--cluster=jenvtest",
2430
"--namespace=default", "--user=jenvtest");
25-
execAndWait("kubectl", "config", "use-context", "jenvtest");
31+
execWithKubectlConfigAndWait("use-context", JENVTEST);
2632
}
2733

2834
public void cleanupFromKubeConfig() {
2935
log.debug("Cleanig up kubeconfig");
30-
unset("contexts.jenvtest");
31-
unset("clusters.jenvtest");
32-
unset("users.jenvtest");
36+
unset("contexts."+JENVTEST);
37+
unset("clusters."+JENVTEST);
38+
unset("users."+JENVTEST);
3339
}
3440

3541
private void unset(String target) {
36-
execAndWait("kubectl","config","unset", target);
42+
execWithKubectlConfigAndWait("unset", target);
3743
}
3844

39-
private void execAndWait(String... arguments) {
45+
private void execWithKubectlConfigAndWait(String... arguments) {
4046
try {
41-
var process = new ProcessBuilder(arguments).start();
47+
List<String> args = new ArrayList<>(arguments.length+2);
48+
args.add(binaryManager.binaries().getKubectl().getPath());
49+
args.add("config");
50+
args.addAll(List.of(arguments));
51+
var process = new ProcessBuilder(args).start();
4252
process.waitFor();
43-
} catch (InterruptedException | IOException e) {
53+
} catch (IOException e) {
54+
throw new KubeApiException(e);
55+
} catch (InterruptedException e) {
56+
Thread.currentThread().interrupt();
4457
throw new KubeApiException(e);
4558
}
4659
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.csviri.kubeapi;
2+
3+
import java.util.Comparator;
4+
import java.util.List;
5+
6+
public class SemverUtil {
7+
8+
private static SemverComparator semverComparator = new SemverComparator();
9+
10+
11+
public static final String getLatestVersion(List<String> versions) {
12+
versions.sort(semverComparator);
13+
return versions.get(versions.size()-1);
14+
}
15+
16+
private static class SemverComparator implements Comparator<String> {
17+
@Override
18+
public int compare(String v1, String v2) {
19+
String[] thisParts = v1.split("\\.");
20+
String[] thatParts = v2.split("\\.");
21+
int length = Math.max(thisParts.length, thatParts.length);
22+
for(int i = 0; i < length; i++) {
23+
int thisPart = i < thisParts.length ?
24+
Integer.parseInt(thisParts[i]) : 0;
25+
int thatPart = i < thatParts.length ?
26+
Integer.parseInt(thatParts[i]) : 0;
27+
if(thisPart < thatPart)
28+
return -1;
29+
if(thisPart > thatPart)
30+
return 1;
31+
}
32+
return 0;
33+
}
34+
}
35+
36+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.csviri.kubeapi;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
class SemverUtilTest {
11+
12+
@Test
13+
void getsLatestVersion() {
14+
assertThat(SemverUtil.getLatestVersion(new ArrayList<>(List.of("1.22.4","1.26.3","1.26.1","1.11.2"))))
15+
.isEqualTo("1.26.3");
16+
}
17+
}

0 commit comments

Comments
 (0)