Skip to content

Commit 89c3841

Browse files
committed
fix: allow multiple configs listed in KUBECONFIG (redhat-developer#779)
Signed-off-by: Andre Dietisheim <[email protected]>
1 parent 911769e commit 89c3841

File tree

6 files changed

+3067
-2
lines changed

6 files changed

+3067
-2
lines changed

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

+1,849
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (C) 2015 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.fabric8.kubernetes.client;
17+
18+
import io.fabric8.kubernetes.api.model.Config;
19+
import io.fabric8.kubernetes.client.internal.KubeConfigUtils;
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import java.io.File;
24+
import java.io.IOException;
25+
26+
public class KubeConfigFile {
27+
28+
private static final Logger LOGGER = LoggerFactory.getLogger(KubeConfigFile.class);
29+
30+
private final File file;
31+
private boolean parsed = false;
32+
private Config config;
33+
34+
public KubeConfigFile(String file) {
35+
this(new File(file), null);
36+
}
37+
38+
public KubeConfigFile(File file) {
39+
this(file, null);
40+
}
41+
42+
private KubeConfigFile(File file, Config config) {
43+
this.file = file;
44+
this.config = config;
45+
}
46+
47+
public File getFile() {
48+
return file;
49+
}
50+
51+
public Config getConfig() {
52+
if (!parsed) {
53+
this.config = createConfig(file);
54+
this.parsed = true;
55+
}
56+
return config;
57+
}
58+
59+
private Config createConfig(File file) {
60+
Config config = null;
61+
try {
62+
if (isReadable(file)) {
63+
LOGGER.debug("Found for Kubernetes config at: [{}].", file.getPath());
64+
config = KubeConfigUtils.parseConfig(file);
65+
}
66+
} catch (IOException e) {
67+
LOGGER.debug("Kubernetes file at [{}] is not a valid config. Ignoring.", file.getPath(), e);
68+
}
69+
return config;
70+
}
71+
72+
public boolean isReadable() {
73+
return isReadable(file);
74+
}
75+
76+
private boolean isReadable(File file) {
77+
try {
78+
return file != null
79+
&& file.isFile();
80+
} catch (SecurityException e) {
81+
return false;
82+
}
83+
}
84+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
/*
2+
* Copyright (C) 2015 Red Hat, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.fabric8.kubernetes.client.internal;
17+
18+
import io.fabric8.kubernetes.api.model.AuthInfo;
19+
import io.fabric8.kubernetes.api.model.Cluster;
20+
import io.fabric8.kubernetes.api.model.Config;
21+
import io.fabric8.kubernetes.api.model.ConfigBuilder;
22+
import io.fabric8.kubernetes.api.model.Context;
23+
import io.fabric8.kubernetes.api.model.NamedAuthInfo;
24+
import io.fabric8.kubernetes.api.model.NamedCluster;
25+
import io.fabric8.kubernetes.api.model.NamedContext;
26+
import io.fabric8.kubernetes.api.model.NamedExtension;
27+
import io.fabric8.kubernetes.api.model.PreferencesBuilder;
28+
import io.fabric8.kubernetes.client.utils.Serialization;
29+
import io.fabric8.kubernetes.client.utils.Utils;
30+
31+
import java.io.File;
32+
import java.io.FileInputStream;
33+
import java.io.FileWriter;
34+
import java.io.IOException;
35+
import java.util.List;
36+
37+
/**
38+
* Helper class for working with the YAML config file thats located in
39+
* <code>~/.kube/config</code> which is updated when you use commands
40+
* like <code>osc login</code> and <code>osc project myproject</code>
41+
*/
42+
public class KubeConfigUtils {
43+
private KubeConfigUtils() {
44+
}
45+
46+
public static Config parseConfig(File file) throws IOException {
47+
return Serialization.unmarshal(new FileInputStream(file), Config.class);
48+
}
49+
50+
public static Config parseConfigFromString(String contents) {
51+
return Serialization.unmarshal(contents, Config.class);
52+
}
53+
54+
/**
55+
* Returns the current context in the given config
56+
*
57+
* @param config Config object
58+
* @return returns context in config if found, otherwise null
59+
*/
60+
public static NamedContext getCurrentContext(Config config) {
61+
String contextName = config.getCurrentContext();
62+
if (contextName != null) {
63+
List<NamedContext> contexts = config.getContexts();
64+
if (contexts != null) {
65+
for (NamedContext context : contexts) {
66+
if (contextName.equals(context.getName())) {
67+
return context;
68+
}
69+
}
70+
}
71+
}
72+
return null;
73+
}
74+
75+
/**
76+
* Returns the current user token for the config and current context
77+
*
78+
* @param config Config object
79+
* @param context Context object
80+
* @return returns current user based upon provided parameters.
81+
*/
82+
public static String getUserToken(Config config, Context context) {
83+
AuthInfo authInfo = getUserAuthInfo(config, context);
84+
if (authInfo != null) {
85+
return authInfo.getToken();
86+
}
87+
return null;
88+
}
89+
90+
/**
91+
* Returns the current {@link AuthInfo} for the current context and user
92+
*
93+
* @param config Config object
94+
* @param context Context object
95+
* @return {@link AuthInfo} for current context
96+
*/
97+
public static AuthInfo getUserAuthInfo(Config config, Context context) {
98+
AuthInfo authInfo = null;
99+
if (config != null && context != null) {
100+
String user = context.getUser();
101+
if (user != null) {
102+
List<NamedAuthInfo> users = config.getUsers();
103+
if (users != null) {
104+
authInfo = users.stream()
105+
.filter(u -> u.getName().equals(user))
106+
.findAny()
107+
.map(NamedAuthInfo::getUser)
108+
.orElse(null);
109+
}
110+
}
111+
}
112+
return authInfo;
113+
}
114+
115+
/**
116+
* Returns the current {@link Cluster} for the current context
117+
*
118+
* @param config {@link Config} config object
119+
* @param context {@link Context} context object
120+
* @return current {@link Cluster} for current context
121+
*/
122+
public static Cluster getCluster(Config config, Context context) {
123+
Cluster cluster = null;
124+
if (config != null && context != null) {
125+
String clusterName = context.getCluster();
126+
if (clusterName != null) {
127+
List<NamedCluster> clusters = config.getClusters();
128+
if (clusters != null) {
129+
cluster = clusters.stream()
130+
.filter(c -> c.getName().equals(clusterName))
131+
.findAny()
132+
.map(NamedCluster::getCluster)
133+
.orElse(null);
134+
}
135+
}
136+
}
137+
return cluster;
138+
}
139+
140+
/**
141+
* Get User index from Config object
142+
*
143+
* @param config {@link io.fabric8.kubernetes.api.model.Config} Kube Config
144+
* @param userName username inside Config
145+
* @return index of user in users array
146+
*/
147+
public static int getNamedUserIndexFromConfig(Config config, String userName) {
148+
for (int i = 0; i < config.getUsers().size(); i++) {
149+
if (config.getUsers().get(i).getName().equals(userName)) {
150+
return i;
151+
}
152+
}
153+
return -1;
154+
}
155+
156+
/**
157+
* Modify KUBECONFIG file
158+
*
159+
* @param kubeConfig modified {@link io.fabric8.kubernetes.api.model.Config} object
160+
* @param kubeConfigPath path to KUBECONFIG
161+
* @throws IOException in case of failure while writing to file
162+
*/
163+
public static void persistKubeConfigIntoFile(Config kubeConfig, String kubeConfigPath) throws IOException {
164+
try (FileWriter writer = new FileWriter(kubeConfigPath)) {
165+
writer.write(Serialization.asYaml(kubeConfig));
166+
}
167+
}
168+
169+
public static Config merge(Config thisConfig, Config thatConfig) {
170+
if (thisConfig == null) {
171+
return thatConfig;
172+
}
173+
ConfigBuilder builder = new ConfigBuilder(thatConfig);
174+
if (thisConfig.getClusters() != null) {
175+
builder.addAllToClusters(thisConfig.getClusters());
176+
}
177+
if (thisConfig.getContexts() != null) {
178+
builder.addAllToContexts(thisConfig.getContexts());
179+
}
180+
if (thisConfig.getUsers() != null) {
181+
builder.addAllToUsers(thisConfig.getUsers());
182+
}
183+
if (thisConfig.getExtensions() != null) {
184+
builder.addAllToExtensions(thisConfig.getExtensions());
185+
}
186+
if (!builder.hasCurrentContext()
187+
&& Utils.isNotNullOrEmpty(thisConfig.getCurrentContext())) {
188+
builder.withCurrentContext(thisConfig.getCurrentContext());
189+
}
190+
Config merged = builder.build();
191+
mergePreferences(thisConfig, merged);
192+
return merged;
193+
}
194+
195+
public static void mergePreferences(io.fabric8.kubernetes.api.model.Config source,
196+
io.fabric8.kubernetes.api.model.Config destination) {
197+
if (source.getPreferences() != null) {
198+
PreferencesBuilder builder = new PreferencesBuilder(destination.getPreferences());
199+
if (source.getPreferences() != null) {
200+
builder.addToExtensions(source.getExtensions().toArray(new NamedExtension[] {}));
201+
}
202+
destination.setPreferences(builder.build());
203+
}
204+
}
205+
}

0 commit comments

Comments
 (0)