Skip to content

Commit 366f91c

Browse files
authored
Merge pull request #7 from brendandburns/config2
Add support for kubeconfig based client creation.
2 parents b8d40b4 + 0f1f395 commit 366f91c

File tree

8 files changed

+568
-6
lines changed

8 files changed

+568
-6
lines changed

examples/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,10 @@
1414
<artifactId>client-java</artifactId>
1515
<version>1.0-SNAPSHOT</version>
1616
</dependency>
17+
<dependency>
18+
<groupId>io.kubernetes</groupId>
19+
<artifactId>client-java-util</artifactId>
20+
<version>1.0-SNAPSHOT</version>
21+
</dependency>
1722
</dependencies>
1823
</project>

examples/src/main/java/io/kubernetes/client/examples/Example.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
import io.kubernetes.client.apis.CoreV1Api;
77
import io.kubernetes.client.models.V1Pod;
88
import io.kubernetes.client.models.V1PodList;
9+
import io.kubernetes.client.util.Config;
10+
11+
import java.io.IOException;
912

1013
/**
1114
* A simple example of how to use the Java API
@@ -18,9 +21,14 @@
1821
* From inside $REPO_DIR/kubernetes
1922
*/
2023
public class Example {
21-
public static void main(String[] args) throws ApiException{
22-
ApiClient client = new ApiClient();
23-
client.setBasePath("http://localhost:8001");
24+
public static void main(String[] args) throws IOException, ApiException{
25+
ApiClient client;
26+
if (args.length == 0) {
27+
client = new ApiClient();
28+
client.setBasePath("http://localhost:8001");
29+
} else {
30+
client = Config.fromConfig(args[0]);
31+
}
2432
Configuration.setDefaultApiClient(client);
2533

2634
CoreV1Api api = new CoreV1Api();

kubernetes/.swagger-codegen-ignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
.gitignore
22
git_push.sh
3+
# Remove this once swagger-codegen 2.2.3 is released and we update.
4+
# We want https://github.com/swagger-api/swagger-codegen/pull/5629
5+
# in the release.
6+
src/main/java/io/kubernetes/client/ApiClient.java
37

kubernetes/src/main/java/io/kubernetes/client/ApiClient.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464

6565
import javax.net.ssl.HostnameVerifier;
6666
import javax.net.ssl.KeyManager;
67-
import javax.net.ssl.KeyManagerFactory;
6867
import javax.net.ssl.SSLContext;
6968
import javax.net.ssl.SSLSession;
7069
import javax.net.ssl.TrustManager;
@@ -127,6 +126,7 @@ public class ApiClient {
127126

128127
private InputStream sslCaCert;
129128
private boolean verifyingSsl;
129+
private KeyManager[] keyManagers;
130130

131131
private OkHttpClient httpClient;
132132
private JSON json;
@@ -271,6 +271,12 @@ public ApiClient setSslCaCert(InputStream sslCaCert) {
271271
return this;
272272
}
273273

274+
public ApiClient setKeyManagers(KeyManager[] managers) {
275+
this.keyManagers = managers;
276+
applySslSettings();
277+
return this;
278+
}
279+
274280
public DateFormat getDateFormat() {
275281
return dateFormat;
276282
}
@@ -1252,7 +1258,6 @@ private void initDatetimeFormat() {
12521258
*/
12531259
private void applySslSettings() {
12541260
try {
1255-
KeyManager[] keyManagers = null;
12561261
TrustManager[] trustManagers = null;
12571262
HostnameVerifier hostnameVerifier = null;
12581263
if (!verifyingSsl) {

util/pom.xml

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,28 @@
1414
<artifactId>client-java</artifactId>
1515
<version>1.0-SNAPSHOT</version>
1616
</dependency>
17+
<dependency>
18+
<groupId>org.yaml</groupId>
19+
<artifactId>snakeyaml</artifactId>
20+
<version>1.18</version>
21+
</dependency>
22+
<dependency>
23+
<groupId>commons-codec</groupId>
24+
<artifactId>commons-codec</artifactId>
25+
<version>1.10</version>
26+
</dependency>
1727
</dependencies>
18-
</project>
28+
<build>
29+
<plugins>
30+
<plugin>
31+
<groupId>org.apache.maven.plugins</groupId>
32+
<artifactId>maven-compiler-plugin</artifactId>
33+
<version>3.1</version>
34+
<configuration>
35+
<source>1.7</source>
36+
<target>1.7</target>
37+
</configuration>
38+
</plugin>
39+
</plugins>
40+
</build>
41+
</project>

util/src/main/java/io/kubernetes/client/util/Config.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,19 @@
33
import io.kubernetes.client.ApiClient;
44

55
import java.io.BufferedReader;
6+
import java.io.ByteArrayInputStream;
67
import java.io.FileReader;
78
import java.io.FileInputStream;
9+
import java.io.FileNotFoundException;
10+
import java.io.InputStream;
11+
import java.io.InputStreamReader;
812
import java.io.IOException;
13+
import java.io.Reader;
14+
import java.io.UnsupportedEncodingException;
15+
import java.util.List;
16+
17+
import javax.net.ssl.KeyManager;
18+
import javax.net.ssl.KeyManagerFactory;
919

1020
public class Config {
1121
private static final String SERVICEACCOUNT_ROOT =
@@ -63,4 +73,68 @@ public static ApiClient fromToken(String url, String token, boolean validateSSL)
6373
client.setAccessToken(token);
6474
return client;
6575
}
76+
77+
public static ApiClient fromConfig(String fileName) throws IOException {
78+
return fromConfig(new FileReader(fileName));
79+
}
80+
81+
public static ApiClient fromConfig(InputStream stream) {
82+
return fromConfig(new InputStreamReader(stream));
83+
}
84+
85+
public static ApiClient fromConfig(Reader input) {
86+
KubeConfig config = KubeConfig.loadKubeConfig(input);
87+
ApiClient client = new ApiClient();
88+
client.setBasePath(config.getServer());
89+
90+
try {
91+
KeyManager[] mgrs = SSLUtils.keyManagers(
92+
config.getClientCertificateData(),
93+
config.getClientCertificateFile(),
94+
config.getClientKeyData(),
95+
config.getClientKeyFile(),
96+
"RSA", "",
97+
null, null);
98+
client.setKeyManagers(mgrs);
99+
} catch (Exception ex) {
100+
ex.printStackTrace();
101+
}
102+
103+
// It's silly to have to do it in this order, but each SSL setup
104+
// consumes the CA cert, so if we do this before the client certs
105+
// are injected the cert input stream is exhausted and things get
106+
// grumpy'
107+
String caCert = config.getCertificateAuthorityData();
108+
String caCertFile = config.getCertificateAuthorityFile();
109+
if (caCert != null) {
110+
try {
111+
client.setSslCaCert(new ByteArrayInputStream(caCert.getBytes("UTF-8")));
112+
} catch (UnsupportedEncodingException ex) {
113+
ex.printStackTrace();
114+
}
115+
} else if (caCertFile != null) {
116+
try {
117+
client.setSslCaCert(new FileInputStream(caCertFile));
118+
} catch (FileNotFoundException ex) {
119+
ex.printStackTrace();
120+
}
121+
}
122+
123+
String token = config.getAccessToken();
124+
if (token != null) {
125+
client.setAccessToken(token);
126+
}
127+
128+
String username = config.getUsername();
129+
if (username != null) {
130+
client.setUsername(username);
131+
}
132+
133+
String password = config.getPassword();
134+
if (password != null) {
135+
client.setPassword(password);
136+
}
137+
138+
return client;
139+
}
66140
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package io.kubernetes.client.util;
2+
3+
import java.io.File;
4+
import java.io.FileNotFoundException;
5+
import java.io.FileReader;
6+
import java.io.Reader;
7+
import java.util.ArrayList;
8+
import java.util.Map;
9+
10+
import org.yaml.snakeyaml.Yaml;
11+
import org.yaml.snakeyaml.constructor.SafeConstructor;
12+
13+
/**
14+
* KubeConfig represents a kubernetes client configuration
15+
*/
16+
public class KubeConfig {
17+
// Note to the reader: I considered creating a Config object
18+
// and parsing into that instead of using Maps, but honestly
19+
// this seemed cleaner than a bunch of boilerplate classes
20+
21+
private ArrayList<Object> clusters;
22+
private ArrayList<Object> contexts;
23+
private ArrayList<Object> users;
24+
Map<String, Object> currentContext;
25+
Map<String, Object> currentCluster;
26+
Map<String, Object> currentUser;
27+
28+
/**
29+
* Load a Kubernetes config from the default location
30+
*/
31+
public static KubeConfig loadDefaultKubeConfig() throws FileNotFoundException {
32+
File homeDir = new File(System.getenv("HOME"));
33+
File config = new File(new File(homeDir, ".kube"), "config");
34+
return loadKubeConfig(new FileReader(config));
35+
}
36+
37+
/**
38+
* Load a Kubernetes config from a Reader
39+
*/
40+
public static KubeConfig loadKubeConfig(Reader input) {
41+
Yaml yaml = new Yaml(new SafeConstructor());
42+
Object config = yaml.load(input);
43+
Map<String, Object> configMap = (Map<String, Object>)config;
44+
45+
String currentContext = (String)configMap.get("current-context");
46+
ArrayList<Object> contexts = (ArrayList<Object>)configMap.get("contexts");
47+
ArrayList<Object> clusters = (ArrayList<Object>)configMap.get("clusters");
48+
ArrayList<Object> users = (ArrayList<Object>)configMap.get("users");
49+
50+
KubeConfig kubeConfig = new KubeConfig(contexts, clusters, users);
51+
kubeConfig.setContext(currentContext);
52+
53+
return kubeConfig;
54+
}
55+
56+
public KubeConfig(ArrayList<Object> contexts,
57+
ArrayList<Object> clusters,
58+
ArrayList<Object> users) {
59+
this.contexts = contexts;
60+
this.clusters = clusters;
61+
this.users = users;
62+
}
63+
64+
public void setContext(String context) {
65+
currentCluster = null;
66+
currentUser = null;
67+
currentContext = (Map<String, Object>) findObject(contexts, context).get("context");
68+
if (currentContext == null) {
69+
return;
70+
}
71+
String cluster = (String) currentContext.get("cluster");
72+
String user = (String) currentContext.get("user");
73+
74+
if (cluster != null) {
75+
currentCluster = (Map<String, Object>) findObject(clusters, cluster).get("cluster");
76+
}
77+
if (user != null) {
78+
currentUser = (Map<String, Object>) findObject(users, user).get("user");
79+
}
80+
}
81+
82+
public String getServer() {
83+
return getData(currentCluster, "server");
84+
}
85+
86+
public String getCertificateAuthorityData() {
87+
return getData(currentCluster, "certificate-authority-data");
88+
}
89+
90+
public String getCertificateAuthorityFile() {
91+
return getData(currentCluster, "certificate-authority");
92+
}
93+
94+
public String getClientCertificateFile() {
95+
return getData(currentUser, "client-certificate");
96+
}
97+
98+
public String getClientCertificateData() {
99+
return getData(currentUser, "client-certificate-data");
100+
}
101+
102+
public String getClientKeyFile() {
103+
return getData(currentUser, "client-key");
104+
}
105+
106+
public String getClientKeyData() {
107+
return getData(currentUser, "client-key-data");
108+
}
109+
110+
public String getUsername() {
111+
return getData(currentUser, "username");
112+
}
113+
114+
public String getPassword() {
115+
return getData(currentUser, "password");
116+
}
117+
118+
public String getAccessToken() {
119+
if (currentUser == null) {
120+
return null;
121+
}
122+
Object authProvider = currentUser.get("auth-provider");
123+
if (authProvider != null) {
124+
Map<String, Object> authProviderMap = (Map<String, Object>) authProvider;
125+
Map<String, Object> authConfig = (Map<String, Object>) authProviderMap.get("config");
126+
if (authConfig != null) {
127+
return (String) authConfig.get("access-token");
128+
}
129+
}
130+
return null;
131+
}
132+
133+
private static String getData(Map<String, Object> obj, String key) {
134+
if (obj == null) {
135+
return null;
136+
}
137+
return (String) obj.get(key);
138+
}
139+
140+
private static Map<String, Object> findObject(ArrayList<Object> list, String name) {
141+
for (Object obj : list) {
142+
Map<String, Object> map = (Map<String, Object>)obj;
143+
if (name.equals((String)map.get("name"))) {
144+
return map;
145+
}
146+
}
147+
return null;
148+
}
149+
}

0 commit comments

Comments
 (0)