diff --git a/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java b/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java new file mode 100644 index 0000000000..6d6063e019 --- /dev/null +++ b/util/src/main/java/io/kubernetes/client/util/ClientBuilder.java @@ -0,0 +1,242 @@ +/* +Copyright 2017 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ +package io.kubernetes.client.util; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import javax.net.ssl.KeyManager; + +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + +import okio.ByteString; +import io.kubernetes.client.ApiClient; +import io.kubernetes.client.util.Config; +import io.kubernetes.client.util.KubeConfig; + +public class ClientBuilder { + + private boolean verifyingSsl = false; + private String basePath = null; + private File certificateAuthorityFile = null; + private String certificateAuthorityData = null; + private String apiKey = null; + private String userName = null; + private String password = null; + private KeyManager[] keyMgrs = null; + private String accessToken = null; + private String apiKeyPrefix = null; + private KubeConfig kubeConfig = null; + private ApiClient client = null; + + private static final Logger log = Logger.getLogger(Config.class); + + public String getUserName() { + return userName; + } + + public ClientBuilder setUserName(String userName) { + this.userName = userName; + return this; + } + + public String getPassword() { + return password; + } + + public ClientBuilder setPassword(String password) { + this.password = password; + return this; + } + + public String getApiKey() { + return apiKey; + } + + public ClientBuilder setApiKey(String apiKey) { + this.apiKey = apiKey; + return this; + } + + public String getBasePath() { + return basePath; + } + + public ClientBuilder setBasePath(String basePath) { + this.basePath = basePath; + return this; + } + + public File getCertificateAuthorityFile() { + return certificateAuthorityFile; + } + + public ClientBuilder setCertificateAuthority(File certificateAuthorityFile) { + this.certificateAuthorityFile = certificateAuthorityFile; + this.verifyingSsl = true; + return this; + } + + public String getCertificateAuthorityData() { + return certificateAuthorityData; + } + + public ClientBuilder setCertificateAuthority(String certificateAuthorityData) { + this.certificateAuthorityData = certificateAuthorityData; + this.verifyingSsl = true; + return this; + } + + public ClientBuilder setClusterMode() throws IOException { + this.client = Config.fromCluster(); + return this; + } + + public ClientBuilder setKubeConfig(KubeConfig config) { + this.kubeConfig = config; + if( this.kubeConfig !=null) { + this.client = Config.fromConfig(this.kubeConfig); + } + return this; + } + + public ClientBuilder setDefaultKubeConfigMode() throws FileNotFoundException { + this.client = Config.fromConfig(KubeConfig.loadDefaultKubeConfig()); + return this; + } + + public ClientBuilder setKubeConfig(File kubeFile) throws FileNotFoundException { + this.kubeConfig = KubeConfig.loadKubeConfig(new FileReader(kubeFile)); + return this; + } + + public ClientBuilder setKubeConfig(Reader input) { + this.kubeConfig = KubeConfig.loadKubeConfig(input); + return this; + } + + public ClientBuilder setKubeConfig(InputStream stream) { + this.kubeConfig = KubeConfig.loadKubeConfig(new InputStreamReader(stream)); + return this; + } + + public KeyManager[] getKeyMgrs() { + return keyMgrs; + } + + public ClientBuilder setKeyMgrs(KeyManager[] keyMgrs) { + this.keyMgrs = keyMgrs; + return this; + } + + public boolean isVerifyingSsl() { + return verifyingSsl; + } + + public ClientBuilder setVerifyingSsl(boolean verifyingSsl) { + this.verifyingSsl = verifyingSsl; + return this; + } + + + public ClientBuilder setDefaultClientMode() throws IOException { + client = Config.defaultClient(); + return this; + } + + public String getApiKeyPrefix() { + return apiKeyPrefix; + } + + public ClientBuilder setApiKeyPrefix(String apiKeyPrefix) { + this.apiKeyPrefix = apiKeyPrefix; + return this; + } + + public ApiClient build() throws FileNotFoundException { + if(client == null) { + client = new ApiClient(); + } + + String localBasePath = client.getBasePath(); + + if (basePath != null) { + if(basePath.endsWith("/")) { + basePath = basePath.substring(0, basePath.length() - 1); + } + client.setBasePath(basePath); + }else { + if (localBasePath.length() == 0) { + client.setBasePath("http://localhost:8080"); + } + } + + if(keyMgrs != null) { + client.setKeyManagers(keyMgrs); + } + + if(userName != null){ + client.setUsername(userName); + } + + if(password != null){ + client.setPassword(password); + } + + if(( userName != null )&&(password != null)) { + final String usernameAndPassword = userName + ":" + password; + client.setApiKeyPrefix("Basic"); + client.setApiKey(ByteString.of(usernameAndPassword.getBytes(Charset.forName("ISO-8859-1"))).base64()); + } + + if(accessToken != null) { + if (apiKeyPrefix == null){ + client.setApiKeyPrefix("Bearer"); + } + client.setAccessToken(accessToken); + } + + if(apiKeyPrefix != null) { + client.setApiKeyPrefix(apiKeyPrefix); + } + + if(apiKey != null) { + if (apiKeyPrefix == null){ + client.setApiKeyPrefix("Bearer"); + } + client.setApiKey(apiKey); + } + + client.setVerifyingSsl(verifyingSsl); + + if(certificateAuthorityFile != null) { + client.setSslCaCert(new FileInputStream(certificateAuthorityFile)); + } + + if(certificateAuthorityData != null) { + byte[] bytes = Base64.decodeBase64(certificateAuthorityData); + client.setSslCaCert(new ByteArrayInputStream(bytes)); + } + + return client; + } +} \ No newline at end of file diff --git a/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java b/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java new file mode 100644 index 0000000000..0027cbc65f --- /dev/null +++ b/util/src/test/java/io/kubernetes/client/util/ClientBuilderTest.java @@ -0,0 +1,253 @@ +/* +Copyright 2017 The Kubernetes Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + */ +package io.kubernetes.client.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.Charset; + +import javax.net.ssl.KeyManager; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.EnvironmentVariables; +import org.junit.rules.TemporaryFolder; + +import io.kubernetes.client.ApiClient; +import okio.ByteString; + +/** + * Tests for the ConfigBuilder helper class + */ +public class ClientBuilderTest { + String basePath = "http://localhost"; + String apiKey = "ABCD"; + String userName = "userName"; + String password = "password"; + String apiKeyPrefix = "Bearer"; + String certificateAuthorityData = null; + String certificateAuthorityFile = "/home/user/.minikube/ca.crt"; + String clientCertData = null; + String clientCertFile = "/home/user/.minikube/apiserver.crt"; + String clientKeyData = null; + String clientKeyFile = "/home/user/.minikube/apiserver.key"; + String algo = "RSA"; + String passphrase = ""; + String keyStoreFile = null ; + String keyStorePassphrase = null; + KeyManager[] keyMgrs =null; + + @Rule + public final EnvironmentVariables environmentVariables + = new EnvironmentVariables(); + + @Rule + public TemporaryFolder folder= new TemporaryFolder(); + + + @Test + public void testDefaultClientNothingPresent() { + environmentVariables.set("HOME", "/non-existent"); + ApiClient client; + try { + client = (new ClientBuilder()) + .setDefaultClientMode() + .build(); + assertEquals("http://localhost:8080", client.getBasePath()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + public static String HOME_CONFIG = + "apiVersion: v1\n" + + "clusters:\n" + + "- cluster:\n" + + " server: http://home.dir.com\n" + + " name: foo\n" + + "contexts:\n" + + "- context:\n" + + " cluster: foo\n" + + " name: foo-context\n" + + "current-context: foo-context\n"; + + public static String KUBECONFIG = + "apiVersion: v1\n" + + "clusters:\n" + + "- cluster:\n" + + " server: http://kubeconfig.dir.com\n" + + " name: foo\n" + + "contexts:\n" + + "- context:\n" + + " cluster: foo\n" + + " name: foo-context\n" + + "current-context: foo-context\n"; + + File config = null; + File dir = null; + File kubedir = null; + File configFile = null; + + @Before + public void setUp() throws IOException { + dir = folder.newFolder(); + kubedir = new File(dir, ".kube"); + kubedir.mkdir(); + config = new File(kubedir, "config"); + FileWriter writer = new FileWriter(config); + writer.write(HOME_CONFIG); + writer.flush(); + writer.close(); + + configFile = folder.newFile("config"); + writer = new FileWriter(configFile); + writer.write(KUBECONFIG); + writer.flush(); + writer.close(); + } + + @Test + public void testDefaultClientHomeDir() { + try { + environmentVariables.set("HOME", dir.getCanonicalPath()); + ApiClient client = new ClientBuilder() + .setDefaultClientMode() + .build(); + assertEquals("http://home.dir.com", client.getBasePath()); + } catch (Exception ex) { + ex.printStackTrace(); + fail("Unexpected exception: " + ex); + } + } + + @Test + public void testDefaultClientKubeConfig() { + try { + environmentVariables.set("KUBECONFIG", configFile.getCanonicalPath()); + ApiClient client = new ClientBuilder() + .setDefaultClientMode() + .build(); + assertEquals("http://kubeconfig.dir.com", client.getBasePath()); + } catch (Exception ex) { + ex.printStackTrace(); + fail("Unexpected exception: " + ex); + } + } + + @Test + public void testDefaultClientPrecedence() { + try { + environmentVariables.set("HOME", dir.getCanonicalPath()); + environmentVariables.set("KUBECONFIG", configFile.getCanonicalPath()); + ApiClient client = new ClientBuilder() + .setDefaultClientMode() + .build(); + // $KUBECONFIG should take precedence over $HOME/.kube/config + assertEquals("http://kubeconfig.dir.com", client.getBasePath()); + } catch (Exception ex) { + ex.printStackTrace(); + fail("Unexpected exception: " + ex); + } + } + + @Test + public void testUserNamePasswordClientBuilder() { + try { + ApiClient client = (new ClientBuilder()) + .setBasePath(basePath) + .setUserName(userName) + .setPassword(password) + .build(); + assertEquals(userName, ((io.kubernetes.client.auth.HttpBasicAuth)client.getAuthentication("BasicAuth")).getUsername()); + assertEquals(password, ((io.kubernetes.client.auth.HttpBasicAuth)client.getAuthentication("BasicAuth")).getPassword()); + assertEquals(basePath, client.getBasePath()); + assertEquals(false, client.isVerifyingSsl()); + assertEquals("Basic", ((io.kubernetes.client.auth.ApiKeyAuth)client.getAuthentications().get("BearerToken")).getApiKeyPrefix()); + assertEquals(ByteString.of((userName+":"+password).getBytes(Charset.forName("ISO-8859-1"))).base64(), ((io.kubernetes.client.auth.ApiKeyAuth)client.getAuthentications().get("BearerToken")).getApiKey()); + } + catch (Exception e) { + e.printStackTrace(); + fail("Unexpected exception: " + e); + } + } + + @Test + public void testApiKeyConfigbuilder() { + ApiClient client = null; + try { + client = (new ClientBuilder()) + .setBasePath(basePath) + .setApiKeyPrefix(apiKeyPrefix) + .setApiKey(apiKey) + .build(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + assertEquals(basePath, client.getBasePath()); + assertEquals(false, client.isVerifyingSsl()); + assertEquals(apiKeyPrefix, ((io.kubernetes.client.auth.ApiKeyAuth)client.getAuthentications().get("BearerToken")).getApiKeyPrefix()); + assertEquals( apiKey, ((io.kubernetes.client.auth.ApiKeyAuth)client.getAuthentications().get("BearerToken")).getApiKey()); + assertEquals(null,((io.kubernetes.client.auth.HttpBasicAuth)client.getAuthentications().get("BasicAuth")).getUsername()); + } + + @Test + public void testKeyMgrANDCertConfigBUilder() { + // will not fail even if file not found exception occurs for clientCertFile + try{ + keyMgrs = SSLUtils.keyManagers(clientCertData, clientCertFile, clientKeyData, clientKeyFile, algo, passphrase, keyStoreFile, keyStorePassphrase); + //by default verify ssl is false + ApiClient client = (new ClientBuilder()) + .setBasePath(basePath) + .setKeyMgrs(keyMgrs) + .setCertificateAuthority(certificateAuthorityData) + .setVerifyingSsl(true) + .build(); + assertEquals(basePath, client.getBasePath()); + assertEquals(true, client.isVerifyingSsl()); + //below assert is not appropriate + //assertSame(keyMgrs, client.getKeyManagers()); + } + catch(Exception e){ + //e.printStackTrace(); + } + } + + @Test + public void testBasePath() throws IOException { + ApiClient client = null ; + client = (new ClientBuilder()) + .setUserName("user") + .build(); + + environmentVariables.set("HOME", "/non-existent"); + client = (new ClientBuilder()) + .setDefaultClientMode() + .setUserName("user") + .build(); + assertEquals("http://localhost:8080", client.getBasePath()); + environmentVariables.set("KUBECONFIG", configFile.getCanonicalPath()); + client = new ClientBuilder() + .setDefaultClientMode() + .setBasePath("http://testkubeconfig.dir.com") + .build(); + assertEquals("http://testkubeconfig.dir.com", client.getBasePath()); + } +}