diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..927fbbdf --- /dev/null +++ b/.gitignore @@ -0,0 +1,77 @@ +# Created by .ignore support plugin (hsz.mobi) +### Maven template +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + + +### Java template +*.class + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.ear + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + + +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion + +*.iml + +## Directory-based project format: +.idea/ +# if you remove the above rule, at least ignore the following: + +# User-specific stuff: +# .idea/workspace.xml +# .idea/tasks.xml +# .idea/dictionaries + +# Sensitive or high-churn files: +# .idea/dataSources.ids +# .idea/dataSources.xml +# .idea/sqlDataSources.xml +# .idea/dynamic.xml +# .idea/uiDesigner.xml + +# Gradle: +# .idea/gradle.xml +# .idea/libraries + +# Mongo Explorer plugin: +# .idea/mongoSettings.xml + +## File-based project format: +*.ipr +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties + + diff --git a/circle.yml b/circle.yml new file mode 100644 index 00000000..de386a7c --- /dev/null +++ b/circle.yml @@ -0,0 +1,28 @@ +# +# Copyright (C) 2015 Red Hat, Inc. +# +# 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. +# + +machine: + java: + version: oraclejdk8 + environment: + JAVA_OPTS: "-Xms256m -Xmx512m" +dependencies: + override: + - mvn install -DskipTests -U +test: + post: + - mkdir -p $CIRCLE_TEST_REPORTS/junit/ + - find . -type f -regex ".*/target/.*-reports/.*xml" -exec cp {} $CIRCLE_TEST_REPORTS/junit/ \; diff --git a/header.txt b/header.txt new file mode 100644 index 00000000..12de4d4c --- /dev/null +++ b/header.txt @@ -0,0 +1,13 @@ +Copyright (C) ${project.inceptionYear} ${owner} + +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. diff --git a/license.txt b/license.txt new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/license.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..f2b12557 --- /dev/null +++ b/pom.xml @@ -0,0 +1,294 @@ + + + + + 4.0.0 + + + org.sonatype.oss + oss-parent + 9 + + + io.fabric8 + spring-cloud-kubernetes-project + 0.0.1-SNAPSHOT + pom + Fabric8 :: Spring Cloud Kubernetes :: Project + + http://fabric8.io/ + 2016 + + + Red Hat + http://redhat.com + + + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + + + + geeks + Fabric8 Development Team + fabric8 + http://fabric8.io/ + + + + + scm:git:git@github.com:fabric8io/kubeflix.git + scm:git:git@github.com:fabric8io/kubeflix.git + http://github.com/fabric8io/kubeflix/ + ${project.version} + + + + + oss-sonatype-staging + Sonatype Staging Repository + https://oss.sonatype.org/service/local/staging/deploy/maven2 + + + + + + 1.3.74 + 1.16.8 + + 1.3.3.RELEASE + 1.0.4.RELEASE + 1.0.6.RELEASE + + + 0.14.2 + 2.2.98 + 9.3.7.v20160115 + 3.5 + 2.6 + + + + spring-cloud-kubernetes-discovery + spring-cloud-kubernetes-core + spring-cloud-kubernetes-all + + + + + + + io.fabric8 + sping-cloud-kubernetes-core + ${project.version} + + + io.fabric8 + sping-cloud-kubernetes-discovery + ${project.version} + + + + io.fabric8 + kubernetes-client + ${kubernetes-client.version} + + + org.springframework.boot + spring-boot-actuator + ${spring-boot.version} + + + org.springframework.boot + spring-boot-autoconfigure + ${spring-boot.version} + + + org.springframework.cloud + spring-cloud-commons + ${spring-cloud.version} + + + org.springframework.cloud + spring-cloud-context + ${spring-cloud.version} + + + org.projectlombok + lombok + 1.16.8 + provided + true + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + true + + 1.8 + 1.8 + + + + + + + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + + + sign-artifacts + verify + + sign + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 1.3.1 + + + enforce-no-snapshots + + enforce + + + + + No Snapshots Allowed! + + + false + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + ${javadoc.include.deps} + + ${javadoc.source.includes} + + ${javadoc.package.excludes} + + + + attach-javadocs + + jar + + + ${javadoc.opts} + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + attach-sources + + jar + + + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin.version} + + + + build + push + + package + + + + + + + + docker + + + + io.fabric8 + docker-maven-plugin + ${docker-maven-plugin.version} + + + docker-build + + build + + package + + + docker-push + + push + + deploy + + + + + + + + doclint-java8-disable + + [1.8,) + + + -Xdoclint:none + + + + diff --git a/spring-cloud-kubernetes-all/pom.xml b/spring-cloud-kubernetes-all/pom.xml new file mode 100644 index 00000000..b7d21a4e --- /dev/null +++ b/spring-cloud-kubernetes-all/pom.xml @@ -0,0 +1,44 @@ + + + + + + spring-cloud-kubernetes-project + io.fabric8 + 0.0.1-SNAPSHOT + + 4.0.0 + + io.fabric8 + spring-cloud-kubernetes-all + Fabric8 :: Spring Cloud Kubernetes :: All + + + + io.fabric8 + sping-cloud-kubernetes-core + + + + io.fabric8 + sping-cloud-kubernetes-discovery + + + + \ No newline at end of file diff --git a/spring-cloud-kubernetes-core/pom.xml b/spring-cloud-kubernetes-core/pom.xml new file mode 100644 index 00000000..7b02b703 --- /dev/null +++ b/spring-cloud-kubernetes-core/pom.xml @@ -0,0 +1,46 @@ + + + + + + io.fabric8 + spring-cloud-kubernetes-project + 0.0.1-SNAPSHOT + + 4.0.0 + + sping-cloud-kubernetes-core + Fabric8 :: Spring Cloud Kubernetes :: Core + + + + io.fabric8 + kubernetes-client + + + org.springframework.boot + spring-boot-actuator + + + org.springframework.boot + spring-boot-autoconfigure + + + + \ No newline at end of file diff --git a/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesAutoConfiguration.java b/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesAutoConfiguration.java new file mode 100644 index 00000000..b6edccfd --- /dev/null +++ b/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesAutoConfiguration.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.kubernetes; + +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.ConfigBuilder; +import io.fabric8.kubernetes.client.DefaultKubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true) +@EnableConfigurationProperties(KubernetesClientProperties.class) +public class KubernetesAutoConfiguration { + + @Autowired + private KubernetesClientProperties properties; + + @Bean + @ConditionalOnMissingBean(Config.class) + public Config kubernetesClientConfig() { + Config base = new Config(); + Config properites = new ConfigBuilder(base) + //Only set values that have been explicitly specified + .withMasterUrl(or(properties.getMasterUrl(), base.getMasterUrl())) + .withMasterUrl(or(properties.getApiVersion(), base.getApiVersion())) + .withMasterUrl(or(properties.getApiVersion(), base.getMasterUrl())) + .withUsername(or(properties.getUsername(), base.getUsername())) + .withPassword(or(properties.getPassword(), base.getPassword())) + + .withCaCertFile(or(properties.getCaCertFile(), base.getCaCertFile())) + .withCaCertData(or(properties.getCaCertData(), base.getCaCertData())) + + .withClientKeyFile(or(properties.getClientKeyFile(), base.getClientKeyFile())) + .withClientKeyData(or(properties.getClientKeyData(), base.getClientKeyData())) + + .withClientCertFile(or(properties.getClientCertFile(), base.getClientCertFile())) + .withClientCertData(or(properties.getClientCertData(), base.getClientCertData())) + + //No magic is done for the properties below so we leave them as is. + .withClientKeyAlgo(or(properties.getClientKeyAlgo(), base.getClientKeyAlgo())) + .withClientKeyPassphrase(or(properties.getClientKeyPassphrase(), base.getClientKeyPassphrase())) + .withConnectionTimeout(or(properties.getConnectionTimeout(), base.getConnectionTimeout())) + .withRequestTimeout(or(properties.getRequestTimeout(), base.getRequestTimeout())) + .withRollingTimeout(or(properties.getRollingTimeout(), base.getRollingTimeout())) + .withTrustCerts(or(properties.isTrustCerts(), base.isTrustCerts())) + .build(); + + if (!base.equals(properites)) { + System.out.println("Objects different"); + } + + return properites; + } + + @Bean + @ConditionalOnMissingBean + public KubernetesClient kubernetesClient(Config config) { + return new DefaultKubernetesClient(config); + } + + @Bean + @ConditionalOnMissingBean + public KubernetesHealthIndicator kubernetesHealthIndicator(KubernetesClient client) { + return new KubernetesHealthIndicator(client); + } + + private static D or(D dis, D dat) { + if (dis != null) { + return dis; + } else { + return dat; + } + } +} diff --git a/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesClientProperties.java b/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesClientProperties.java new file mode 100644 index 00000000..4d056e6c --- /dev/null +++ b/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesClientProperties.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.kubernetes; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("spring.cloud.kubernetes.client") +public class KubernetesClientProperties { + + private Boolean trustCerts; + private String masterUrl; + private String apiVersion; + private String namespace; + private String caCertFile; + private String caCertData; + private String clientCertFile; + private String clientCertData; + private String clientKeyFile; + private String clientKeyData; + private String clientKeyAlgo; + private String clientKeyPassphrase; + private String username; + private String password; + private Integer watchReconnectInterval; + private Integer watchReconnectLimit; + private Integer connectionTimeout; + private Integer requestTimeout; + private Long rollingTimeout; + private Integer loggingInterval; + + public Boolean isTrustCerts() { + return trustCerts; + } + + public String getMasterUrl() { + return masterUrl; + } + + public String getApiVersion() { + return apiVersion; + } + + public String getNamespace() { + return namespace; + } + + public String getCaCertFile() { + return caCertFile; + } + + public String getCaCertData() { + return caCertData; + } + + public String getClientCertFile() { + return clientCertFile; + } + + public String getClientCertData() { + return clientCertData; + } + + public String getClientKeyFile() { + return clientKeyFile; + } + + public String getClientKeyData() { + return clientKeyData; + } + + public String getClientKeyAlgo() { + return clientKeyAlgo; + } + + public String getClientKeyPassphrase() { + return clientKeyPassphrase; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public Integer getWatchReconnectInterval() { + return watchReconnectInterval; + } + + public Integer getWatchReconnectLimit() { + return watchReconnectLimit; + } + + public Integer getConnectionTimeout() { + return connectionTimeout; + } + + public Integer getRequestTimeout() { + return requestTimeout; + } + + public Long getRollingTimeout() { + return rollingTimeout; + } + + public Integer getLoggingInterval() { + return loggingInterval; + } +} diff --git a/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesHealthIndicator.java b/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesHealthIndicator.java new file mode 100644 index 00000000..a6c125cf --- /dev/null +++ b/spring-cloud-kubernetes-core/src/main/java/io/fabric8/spring/cloud/kubernetes/KubernetesHealthIndicator.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.kubernetes; + +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.client.Config; +import io.fabric8.kubernetes.client.KubernetesClient; +import org.springframework.boot.actuate.health.AbstractHealthIndicator; +import org.springframework.boot.actuate.health.Health; + +import java.nio.file.Paths; + +public class KubernetesHealthIndicator extends AbstractHealthIndicator { + + private static final String HOSTNAME = "HOSTNAME"; + + private String hostName; + private KubernetesClient client; + + public KubernetesHealthIndicator(KubernetesClient client) { + this.client = client; + this.hostName = System.getenv(HOSTNAME); + } + + @Override + protected void doHealthCheck(Health.Builder builder) throws Exception { + try { + Pod current = getCurrentPod(); + if (current != null) { + builder.up() + .withDetail("internal", true) + .withDetail("podName", hostName) + .withDetail("podIp", current.getStatus().getPodIP()) + .withDetail("serviceAccount", current.getSpec().getServiceAccountName()) + .withDetail("nodeName", current.getSpec().getNodeName()) + .withDetail("hostIp", current.getStatus().getHostIP()); + } else { + builder.up() + .withDetail("internal", false); + } + } catch (Exception e) { + builder.down(e); + } + } + + + private Pod getCurrentPod() { + if (isServiceAccountFound() && isHostNameEnvVarPresent()) { + return client.pods().withName(hostName).get(); + } else { + return null; + } + } + + private boolean isHostNameEnvVarPresent() { + return hostName != null && !hostName.isEmpty(); + } + + private boolean isServiceAccountFound() { + return Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_TOKEN_PATH).toFile().exists() && + Paths.get(Config.KUBERNETES_SERVICE_ACCOUNT_CA_CRT_PATH).toFile().exists(); + } +} \ No newline at end of file diff --git a/spring-cloud-kubernetes-core/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-core/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..25406ddf --- /dev/null +++ b/spring-cloud-kubernetes-core/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.fabric8.spring.cloud.kubernetes.KubernetesAutoConfiguration \ No newline at end of file diff --git a/spring-cloud-kubernetes-discovery/pom.xml b/spring-cloud-kubernetes-discovery/pom.xml new file mode 100644 index 00000000..385cdb65 --- /dev/null +++ b/spring-cloud-kubernetes-discovery/pom.xml @@ -0,0 +1,56 @@ + + + + + + io.fabric8 + spring-cloud-kubernetes-project + 0.0.1-SNAPSHOT + + 4.0.0 + + sping-cloud-kubernetes-discovery + Fabric8 :: Spring Cloud Kubernetes :: Discovery + + + + + io.fabric8 + sping-cloud-kubernetes-core + ${project.version} + + + + org.springframework.boot + spring-boot-autoconfigure + true + + + org.springframework.cloud + spring-cloud-commons + true + + + org.springframework.cloud + spring-cloud-context + true + + + + \ No newline at end of file diff --git a/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryAutoConfiguration.java b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryAutoConfiguration.java new file mode 100644 index 00000000..e68f61c8 --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryAutoConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.discovery; + +import io.fabric8.kubernetes.client.KubernetesClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConditionalOnProperty(value = "spring.cloud.kubernetes.enabled", matchIfMissing = true) +public class KubernetesDiscoveryAutoConfiguration { + + @Bean + public KubernetesDiscoveryProperties kubernetesDiscoveryProperties() { + return new KubernetesDiscoveryProperties(); + } + + @Bean + @ConditionalOnMissingBean + public KubernetesDiscoveryClient kubernetesDiscoveryClient(KubernetesClient client, KubernetesDiscoveryProperties properties) { + return new KubernetesDiscoveryClient(client, properties.getServiceName()); + } + + @Bean + public KubernetesDiscoveryLifecycle kubernetesDiscoveryLifecycle(KubernetesClient client, KubernetesDiscoveryProperties properties) { + return new KubernetesDiscoveryLifecycle(client, properties); + } +} diff --git a/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryClient.java b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryClient.java new file mode 100644 index 00000000..241a2d43 --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryClient.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.discovery; + +import io.fabric8.kubernetes.client.KubernetesClient; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.discovery.DiscoveryClient; + +import java.util.List; +import java.util.stream.Collectors; + +public class KubernetesDiscoveryClient implements DiscoveryClient { + + private static final String HOSTNAME = "HOSTNAME"; + + private KubernetesClient client; + private String localServiceId; + + public KubernetesDiscoveryClient() { + } + + public KubernetesDiscoveryClient(KubernetesClient client, String localServiceId) { + this.client = client; + this.localServiceId = localServiceId; + } + + public KubernetesClient getClient() { + return client; + } + + public void setClient(KubernetesClient client) { + this.client = client; + } + + public String getLocalServiceId() { + return localServiceId; + } + + public void setLocalServiceId(String localServiceId) { + this.localServiceId = localServiceId; + } + + @Override + public String description() { + return "Kubernetes Discovery Client"; + } + + @Override + public ServiceInstance getLocalServiceInstance() { + String podName = System.getenv(HOSTNAME); + return client.endpoints().withName(localServiceId).get().getSubsets() + .stream() + .filter(s -> s.getAddresses().iterator().next().getIp().equals(podName)) + .map(s -> new KubernetesServiceInstance(localServiceId, s.getPorts().iterator().next().getName(), s, false)) + .findFirst().get(); + } + + @Override + public List getInstances(String serviceId) { + return client.endpoints().withName(serviceId).get() + .getSubsets() + .stream().map(s -> new KubernetesServiceInstance(serviceId, s.getPorts().iterator().next().getName(), s, false)) + .collect(Collectors.toList()); + + } + + @Override + public List getServices() { + return client.services().list() + .getItems() + .stream().map(s -> s.getMetadata().getName()) + .collect(Collectors.toList()); + } +} diff --git a/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryLifecycle.java b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryLifecycle.java new file mode 100644 index 00000000..10e83c6b --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryLifecycle.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.discovery; + +import io.fabric8.kubernetes.client.KubernetesClient; +import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle; +import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class KubernetesDiscoveryLifecycle extends AbstractDiscoveryLifecycle { + + private KubernetesClient client; + private KubernetesDiscoveryProperties properties; + + private AtomicBoolean running = new AtomicBoolean(false); + + public KubernetesDiscoveryLifecycle(KubernetesClient client, KubernetesDiscoveryProperties properties) { + this.client = client; + this.properties = properties; + } + + @Override + public void start() { + if (!isEnabled()) { + return; + } + if (!isRunning()) { + register(); + getContext().publishEvent(new InstanceRegisteredEvent<>(this, + getConfiguration())); + running.compareAndSet(false, true); + } + } + + @Override + public boolean isRunning() { + return this.running.get(); + } + + + @Override + protected int getConfiguredPort() { + return client.getMasterUrl().getPort(); + } + + @Override + protected void setConfiguredPort(int port) { + + } + + @Override + protected Object getConfiguration() { + return properties; + } + + @Override + protected void register() { + } + + @Override + protected void deregister() { + } + + @Override + protected boolean isEnabled() { + return properties.isEnabled(); + } +} diff --git a/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryProperties.java b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryProperties.java new file mode 100644 index 00000000..0a34fff7 --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesDiscoveryProperties.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.discovery; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties("spring.cloud.kubernetes.discovery") +public class KubernetesDiscoveryProperties { + + private boolean enabled = true; + private String serviceName; + + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getServiceName() { + return serviceName; + } +} diff --git a/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesServiceInstance.java b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesServiceInstance.java new file mode 100644 index 00000000..62e82afb --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/main/java/io/fabric8/spring/cloud/discovery/KubernetesServiceInstance.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2016 to the original 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.fabric8.spring.cloud.discovery; + +import io.fabric8.kubernetes.api.model.EndpointPort; +import io.fabric8.kubernetes.api.model.EndpointSubset; +import org.springframework.cloud.client.ServiceInstance; + +import java.net.URI; +import java.net.URISyntaxException; + +import static io.fabric8.kubernetes.client.utils.Utils.isNotNullOrEmpty; +import static io.fabric8.kubernetes.client.utils.Utils.isNullOrEmpty; + +public class KubernetesServiceInstance implements ServiceInstance { + + private static final String HTTP_PREFIX = "http://"; + private static final String HTTPS_PREFIX = "https://"; + private static final String COLN = ":"; + + private final String serviceId; + private final String portName; + private final EndpointSubset subset; + private final Boolean secure; + + public KubernetesServiceInstance(String serviceId, String portName, EndpointSubset subset, Boolean secure) { + this.serviceId = serviceId; + this.portName = portName; + this.subset = subset; + this.secure = secure; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getHost() { + if (subset.getAddresses().isEmpty()) { + throw new IllegalStateException("Endpoint subset has no addresses."); + } + return subset.getAddresses().get(0).getIp(); + } + + @Override + public int getPort() { + if (subset.getPorts().isEmpty()) { + throw new IllegalStateException("Endpoint subset has no ports."); + } else if (isNullOrEmpty(portName) && subset.getPorts().size() == 1) { + return subset.getPorts().get(0).getPort(); + } else if (isNotNullOrEmpty(portName)) { + for (EndpointPort port : subset.getPorts()) { + if (portName.endsWith(port.getName())) { + return port.getPort(); + } + } + } + throw new IllegalStateException("Endpoint subset has no matching ports."); + } + + @Override + public boolean isSecure() { + return secure; + } + + @Override + public URI getUri() { + StringBuilder sb = new StringBuilder(); + + if (isSecure()) { + sb.append(HTTPS_PREFIX); + } else { + sb.append(HTTP_PREFIX); + } + + sb.append(getHost()).append(COLN).append(getPort()); + try { + return new URI(sb.toString()); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/spring-cloud-kubernetes-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-discovery/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..2414fe28 --- /dev/null +++ b/spring-cloud-kubernetes-discovery/src/main/resources/META-INF/spring.factories @@ -0,0 +1,6 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.fabric8.spring.cloud.discovery.KubernetesDiscoveryAutoConfiguration + +# Discovery Client Configuration +org.springframework.cloud.client.discovery.EnableDiscoveryClient=\ +io.fabric8.spring.cloud.discovery.KubernetesDiscoveryClient \ No newline at end of file