Skip to content

Commit 86571db

Browse files
author
Cole Mickens
committed
config: support loading from kubeconfig string
1 parent 7c74385 commit 86571db

File tree

3 files changed

+78
-32
lines changed

3 files changed

+78
-32
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
* Added support for StorageClass - https://github.com/fabric8io/kubernetes-client/pull/978
99
* Added support for PodSecurityPolicy - https://github.com/fabric8io/kubernetes-client/pull/992
1010
* The client now warns when using Kubernetes alpha or beta resources - https://github.com/fabric8io/kubernetes-client/pull/1010
11+
* A Config can now be built from `Config.fromKubeconfig(kubeconfigFileContents)`: https://github.com/fabric8io/kubernetes-client/pull/1029
1112

1213
Improvements
1314
* Fixed issue of SecurityContextConstraints not working - https://github.com/fabric8io/kubernetes-client/pull/982

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/Config.java

+72-32
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import java.io.File;
3636
import java.io.IOException;
3737
import java.nio.file.Files;
38+
import java.nio.charset.StandardCharsets;
3839
import java.util.HashMap;
3940
import java.util.Map;
4041

@@ -369,56 +370,95 @@ private static String absolutify(File relativeTo, String filename) {
369370
return new File(relativeTo.getParentFile(), filename).getAbsolutePath();
370371
}
371372

373+
public static Config fromKubeconfig(String kubeconfigContents) {
374+
return fromKubeconfig(null, kubeconfigContents, null);
375+
}
376+
377+
// Note: kubeconfigPath is optional (see note on loadFromKubeConfig)
378+
public static Config fromKubeconfig(String context, String kubeconfigContents, String kubeconfigPath) {
379+
// we allow passing context along here, since downstream accepts it
380+
Config config = new Config();
381+
Config.loadFromKubeconfig(config, null, kubeconfigContents, kubeconfigPath);
382+
return config;
383+
}
384+
372385
private static boolean tryKubeConfig(Config config, String context) {
373386
LOGGER.debug("Trying to configure client from Kubernetes config...");
374387
if (Utils.getSystemPropertyOrEnvVar(KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, true)) {
375388
File kubeConfigFile = new File(
376389
Utils.getSystemPropertyOrEnvVar(KUBERNETES_KUBECONFIG_FILE, new File(getHomeDir(), ".kube" + File.separator + "config").toString()));
377390
boolean kubeConfigFileExists = Files.isRegularFile(kubeConfigFile.toPath());
391+
378392
if (kubeConfigFileExists) {
379393
LOGGER.debug("Found for Kubernetes config at: ["+kubeConfigFile.getPath()+"].");
394+
String kubeconfigContents;
380395
try {
381-
io.fabric8.kubernetes.api.model.Config kubeConfig = KubeConfigUtils.parseConfig(kubeConfigFile);
382-
if (context != null) {
383-
kubeConfig.setCurrentContext(context);
384-
}
385-
Context currentContext = KubeConfigUtils.getCurrentContext(kubeConfig);
386-
Cluster currentCluster = KubeConfigUtils.getCluster(kubeConfig, currentContext);
387-
if (currentCluster != null) {
388-
config.setMasterUrl(currentCluster.getServer());
389-
config.setNamespace(currentContext.getNamespace());
390-
config.setTrustCerts(currentCluster.getInsecureSkipTlsVerify() != null && currentCluster.getInsecureSkipTlsVerify());
391-
config.setCaCertFile(absolutify(kubeConfigFile, currentCluster.getCertificateAuthority()));
392-
config.setCaCertData(currentCluster.getCertificateAuthorityData());
393-
AuthInfo currentAuthInfo = KubeConfigUtils.getUserAuthInfo(kubeConfig, currentContext);
394-
if (currentAuthInfo != null) {
395-
config.setClientCertFile(absolutify(kubeConfigFile, currentAuthInfo.getClientCertificate()));
396-
config.setClientCertData(currentAuthInfo.getClientCertificateData());
397-
config.setClientKeyFile(absolutify(kubeConfigFile, currentAuthInfo.getClientKey()));
398-
config.setClientKeyData(currentAuthInfo.getClientKeyData());
399-
config.setOauthToken(currentAuthInfo.getToken());
400-
config.setUsername(currentAuthInfo.getUsername());
401-
config.setPassword(currentAuthInfo.getPassword());
402-
403-
if (Utils.isNullOrEmpty(config.getOauthToken()) && currentAuthInfo.getAuthProvider() != null && !Utils.isNullOrEmpty(currentAuthInfo.getAuthProvider().getConfig().get(ACCESS_TOKEN))) {
404-
config.setOauthToken(currentAuthInfo.getAuthProvider().getConfig().get(ACCESS_TOKEN));
405-
}
406-
407-
config.getErrorMessages().put(401, "Unauthorized! Token may have expired! Please log-in again.");
408-
config.getErrorMessages().put(403, "Forbidden! User "+currentContext.getUser()+ " doesn't have permission.");
409-
}
410-
return true;
411-
}
412-
} catch (IOException e) {
396+
kubeconfigContents = new String(Files.readAllBytes(kubeConfigFile.toPath()), StandardCharsets.UTF_8);
397+
} catch(IOException e) {
413398
LOGGER.error("Could not load Kubernetes config file from {}", kubeConfigFile.getPath(), e);
399+
return false;
414400
}
401+
Config.loadFromKubeconfig(config, context, kubeconfigContents, kubeConfigFile.getPath());
402+
return true;
415403
} else {
416404
LOGGER.debug("Did not find Kubernetes config at: ["+kubeConfigFile.getPath()+"]. Ignoring.");
417405
}
418406
}
419407
return false;
420408
}
421409

410+
// Note: kubeconfigPath is optional
411+
// It is only used to rewrite relative tls asset paths inside kubeconfig when a file is passed, and in the case that
412+
// the kubeconfig references some assets via relative paths.
413+
private static boolean loadFromKubeconfig(Config config, String context, String kubeconfigContents, String kubeconfigPath) {
414+
try {
415+
io.fabric8.kubernetes.api.model.Config kubeConfig = KubeConfigUtils.parseConfigFromString(kubeconfigContents);
416+
if (context != null) {
417+
kubeConfig.setCurrentContext(context);
418+
}
419+
Context currentContext = KubeConfigUtils.getCurrentContext(kubeConfig);
420+
Cluster currentCluster = KubeConfigUtils.getCluster(kubeConfig, currentContext);
421+
if (currentCluster != null) {
422+
config.setMasterUrl(currentCluster.getServer());
423+
config.setNamespace(currentContext.getNamespace());
424+
config.setTrustCerts(currentCluster.getInsecureSkipTlsVerify() != null && currentCluster.getInsecureSkipTlsVerify());
425+
config.setCaCertData(currentCluster.getCertificateAuthorityData());
426+
AuthInfo currentAuthInfo = KubeConfigUtils.getUserAuthInfo(kubeConfig, currentContext);
427+
if (currentAuthInfo != null) {
428+
// rewrite tls asset paths if needed
429+
String caCertFile = currentCluster.getCertificateAuthority();
430+
String clientCertFile = currentAuthInfo.getClientCertificate();
431+
String clientKeyFile = currentAuthInfo.getClientKey();
432+
if (kubeconfigPath != null && !kubeconfigPath.isEmpty()) {
433+
caCertFile = absolutify(new File(kubeconfigPath), currentCluster.getCertificateAuthority());
434+
clientCertFile = absolutify(new File(kubeconfigPath), currentAuthInfo.getClientCertificate());
435+
clientKeyFile = absolutify(new File(kubeconfigPath), currentAuthInfo.getClientKey());
436+
}
437+
config.setCaCertFile(caCertFile);
438+
config.setClientCertFile(clientCertFile);
439+
config.setClientCertData(currentAuthInfo.getClientCertificateData());
440+
config.setClientKeyFile(clientKeyFile);
441+
config.setClientKeyData(currentAuthInfo.getClientKeyData());
442+
config.setOauthToken(currentAuthInfo.getToken());
443+
config.setUsername(currentAuthInfo.getUsername());
444+
config.setPassword(currentAuthInfo.getPassword());
445+
446+
if (Utils.isNullOrEmpty(config.getOauthToken()) && currentAuthInfo.getAuthProvider() != null && !Utils.isNullOrEmpty(currentAuthInfo.getAuthProvider().getConfig().get(ACCESS_TOKEN))) {
447+
config.setOauthToken(currentAuthInfo.getAuthProvider().getConfig().get(ACCESS_TOKEN));
448+
}
449+
450+
config.getErrorMessages().put(401, "Unauthorized! Token may have expired! Please log-in again.");
451+
config.getErrorMessages().put(403, "Forbidden! User "+currentContext.getUser()+ " doesn't have permission.");
452+
}
453+
return true;
454+
}
455+
} catch (IOException e) {
456+
LOGGER.error("Failed to parse the kubeconfig.", e);
457+
}
458+
459+
return false;
460+
}
461+
422462
private static boolean tryNamespaceFromPath(Config config) {
423463
LOGGER.debug("Trying to configure client namespace from Kubernetes service account namespace path...");
424464
if (Utils.getSystemPropertyOrEnvVar(KUBERNETES_TRYNAMESPACE_PATH_SYSTEM_PROPERTY, true)) {

kubernetes-client/src/main/java/io/fabric8/kubernetes/client/internal/KubeConfigUtils.java

+5
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ public static Config parseConfig(File file) throws IOException {
4040
return mapper.readValue(file, Config.class);
4141
}
4242

43+
public static Config parseConfigFromString(String contents) throws IOException {
44+
ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
45+
return mapper.readValue(contents, Config.class);
46+
}
47+
4348
/**
4449
* Returns the current context in the given config
4550
*/

0 commit comments

Comments
 (0)