Skip to content

Commit

Permalink
Fix fabric8io#2215: expose current (named) and all (named) contexts
Browse files Browse the repository at this point in the history
Signed-off-by: Andre Dietisheim <[email protected]>
  • Loading branch information
adietish committed Jun 17, 2020
1 parent 2d1a9d4 commit 74b918a
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 56 deletions.
167 changes: 113 additions & 54 deletions kubernetes-client/src/main/java/io/fabric8/kubernetes/client/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,37 @@

package io.fabric8.kubernetes.client;

import static okhttp3.TlsVersion.TLS_1_2;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

import io.fabric8.kubernetes.api.model.AuthInfo;
import io.fabric8.kubernetes.api.model.Cluster;
import io.fabric8.kubernetes.api.model.ConfigBuilder;
import io.fabric8.kubernetes.api.model.Context;
import io.fabric8.kubernetes.api.model.ExecConfig;
import io.fabric8.kubernetes.api.model.ExecEnvVar;
import io.fabric8.kubernetes.api.model.NamedContext;
import io.fabric8.kubernetes.client.internal.CertUtils;
import io.fabric8.kubernetes.client.internal.KubeConfigUtils;
import io.fabric8.kubernetes.client.internal.SSLUtils;
Expand All @@ -34,24 +55,6 @@
import io.fabric8.kubernetes.client.utils.Utils;
import io.sundr.builder.annotations.Buildable;
import okhttp3.TlsVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import static okhttp3.TlsVersion.TLS_1_2;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true, allowGetters = true, allowSetters = true)
Expand Down Expand Up @@ -158,6 +161,9 @@ public class Config {

private RequestConfig requestConfig = new RequestConfig();

private List<NamedContext> contexts = new ArrayList<>();
private NamedContext currentContext = null;

/**
* fields not used but needed for builder generation.
*/
Expand Down Expand Up @@ -233,14 +239,25 @@ private static Config autoConfigure(Config config, String context) {
}
configFromSysPropsOrEnvVars(config);

if (!config.masterUrl.toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL_PREFIX) && !config.masterUrl.toLowerCase(Locale.ROOT).startsWith(HTTPS_PROTOCOL_PREFIX)) {
config.masterUrl = (SSLUtils.isHttpsAvailable(config) ? HTTPS_PROTOCOL_PREFIX : HTTP_PROTOCOL_PREFIX) + config.masterUrl;
config.masterUrl = ensureHttps(config.masterUrl, config);
config.masterUrl = ensureEndsWithSlash(config.masterUrl);

return config;
}

private static String ensureEndsWithSlash(String masterUrl) {
if (!masterUrl.endsWith("/")) {
masterUrl = masterUrl + "/";
}
return masterUrl;
}

if (!config.masterUrl.endsWith("/")) {
config.masterUrl = config.masterUrl + "/";
private static String ensureHttps(String masterUrl, Config config) {
if (!masterUrl.toLowerCase(Locale.ROOT).startsWith(HTTP_PROTOCOL_PREFIX)
&& !masterUrl.toLowerCase(Locale.ROOT).startsWith(HTTPS_PROTOCOL_PREFIX)) {
masterUrl = (SSLUtils.isHttpsAvailable(config) ? HTTPS_PROTOCOL_PREFIX : HTTP_PROTOCOL_PREFIX) + masterUrl;
}
return config;
return masterUrl;
}

@Deprecated
Expand Down Expand Up @@ -460,41 +477,52 @@ public static Config fromKubeconfig(String kubeconfigContents) throws IOExceptio
public static Config fromKubeconfig(String context, String kubeconfigContents, String kubeconfigPath) {
// we allow passing context along here, since downstream accepts it
Config config = new Config();
Config.loadFromKubeconfig(config, context, kubeconfigContents, kubeconfigPath);
loadFromKubeconfig(config, context, kubeconfigContents, kubeconfigPath);
return config;
}

private static boolean tryKubeConfig(Config config, String context) {
LOGGER.debug("Trying to configure client from Kubernetes config...");
if (Utils.getSystemPropertyOrEnvVar(KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, true)) {
String fileName = Utils.getSystemPropertyOrEnvVar(KUBERNETES_KUBECONFIG_FILE, new File(getHomeDir(), ".kube" + File.separator + "config").toString());
if (!Utils.getSystemPropertyOrEnvVar(KUBERNETES_AUTH_TRYKUBECONFIG_SYSTEM_PROPERTY, true)) {
return false;
}
File kubeConfigFile = new File(getKubeconfigFilename());
if (!kubeConfigFile.isFile()) {
LOGGER.debug("Did not find Kubernetes config at: ["+kubeConfigFile.getPath()+"]. Ignoring.");
return false;
}
LOGGER.debug("Found for Kubernetes config at: [{}].", kubeConfigFile.getPath());
String kubeconfigContents = getKubeconfigContents(kubeConfigFile);
if (kubeconfigContents == null) {
return false;
}
loadFromKubeconfig(config, context, kubeconfigContents, kubeConfigFile.getPath());
return true;
}

// if system property/env var contains multiple files take the first one based on the environment
// we are running in (eg. : for Linux, ; for Windows)
String[] fileNames = fileName.split(File.pathSeparator);
private static String getKubeconfigFilename() {
String fileName = Utils.getSystemPropertyOrEnvVar(KUBERNETES_KUBECONFIG_FILE, new File(getHomeDir(), ".kube" + File.separator + "config").toString());

if (fileNames.length > 1) {
LOGGER.warn("Found multiple Kubernetes config files [{}], using the first one: [{}]. If not desired file, please change it by doing `export KUBECONFIG=/path/to/kubeconfig` on Unix systems or `$Env:KUBECONFIG=/path/to/kubeconfig` on Windows.", fileNames, fileNames[0]);
fileName = fileNames[0];
}
// if system property/env var contains multiple files take the first one based on the environment
// we are running in (eg. : for Linux, ; for Windows)
String[] fileNames = fileName.split(File.pathSeparator);

File kubeConfigFile = new File(fileName);
if (kubeConfigFile.isFile()) {
LOGGER.debug("Found for Kubernetes config at: [{}].", kubeConfigFile.getPath());
String kubeconfigContents;
try (FileReader reader = new FileReader(kubeConfigFile)){
kubeconfigContents = IOHelpers.readFully(reader);
} catch(IOException e) {
LOGGER.error("Could not load Kubernetes config file from {}", kubeConfigFile.getPath(), e);
return false;
}
Config.loadFromKubeconfig(config, context, kubeconfigContents, kubeConfigFile.getPath());
return true;
} else {
LOGGER.debug("Did not find Kubernetes config at: ["+kubeConfigFile.getPath()+"]. Ignoring.");
}
if (fileNames.length > 1) {
LOGGER.warn("Found multiple Kubernetes config files [{}], using the first one: [{}]. If not desired file, please change it by doing `export KUBECONFIG=/path/to/kubeconfig` on Unix systems or `$Env:KUBECONFIG=/path/to/kubeconfig` on Windows.", fileNames, fileNames[0]);
fileName = fileNames[0];
}
return false;
return fileName;
}

private static String getKubeconfigContents(File kubeConfigFile) {
String kubeconfigContents = null;
try (FileReader reader = new FileReader(kubeConfigFile)){
kubeconfigContents = IOHelpers.readFully(reader);
} catch(IOException e) {
LOGGER.error("Could not load Kubernetes config file from {}", kubeConfigFile.getPath(), e);
return null;
}
return kubeconfigContents;
}

// Note: kubeconfigPath is optional
Expand All @@ -503,14 +531,14 @@ private static boolean tryKubeConfig(Config config, String context) {
private static boolean loadFromKubeconfig(Config config, String context, String kubeconfigContents, String kubeconfigPath) {
try {
io.fabric8.kubernetes.api.model.Config kubeConfig = KubeConfigUtils.parseConfigFromString(kubeconfigContents);
if (context != null) {
kubeConfig.setCurrentContext(context);
}
Context currentContext = KubeConfigUtils.getCurrentContext(kubeConfig);
config.setContexts(kubeConfig.getContexts());
Context currentContext = setCurrentContext(context, config, kubeConfig);
Cluster currentCluster = KubeConfigUtils.getCluster(kubeConfig, currentContext);
if (currentContext != null) {
config.setNamespace(currentContext.getNamespace());
}
if (currentCluster != null) {
config.setMasterUrl(currentCluster.getServer());
config.setNamespace(currentContext.getNamespace());
config.setTrustCerts(currentCluster.getInsecureSkipTlsVerify() != null && currentCluster.getInsecureSkipTlsVerify());
config.setDisableHostnameVerification(currentCluster.getInsecureSkipTlsVerify() != null && currentCluster.getInsecureSkipTlsVerify());
config.setCaCertData(currentCluster.getCertificateAuthorityData());
Expand Down Expand Up @@ -597,6 +625,20 @@ private static boolean loadFromKubeconfig(Config config, String context, String

return false;
}

private static Context setCurrentContext(String context, Config config, io.fabric8.kubernetes.api.model.Config kubeConfig) {
if (context != null) {
kubeConfig.setCurrentContext(context);
}
Context currentContext = null;
NamedContext currentNamedContext = KubeConfigUtils.getCurrentContext(kubeConfig);
if (currentNamedContext != null) {
config.setCurrentContext(currentNamedContext);
currentContext = currentNamedContext.getContext();
}
return currentContext;
}

@JsonIgnoreProperties(ignoreUnknown = true)
private static final class ExecCredential {
public String kind;
Expand Down Expand Up @@ -1128,4 +1170,21 @@ public Map<String, String> getCustomHeaders() {
public void setCustomHeaders(Map<String, String> customHeaders) {
this.customHeaders = customHeaders;
}

public List<NamedContext> getContexts() {
return contexts;
}

public void setContexts(List<NamedContext> contexts) {
this.contexts = contexts;
}

public NamedContext getCurrentContext() {
return currentContext;
}

public void setCurrentContext(NamedContext context) {
this.currentContext = context;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ public static Config parseConfigFromString(String contents) throws IOException {
* @param config Config object
* @return returns context in config if found, otherwise null
*/
public static Context getCurrentContext(Config config) {
public static NamedContext getCurrentContext(Config config) {
String contextName = config.getCurrentContext();
if (contextName != null) {
List<NamedContext> contexts = config.getContexts();
if (contexts != null) {
for (NamedContext context : contexts) {
if (contextName.equals(context.getName())) {
return context.getContext();
return context;
}
}
}
Expand Down

0 comments on commit 74b918a

Please sign in to comment.