diff --git a/pom.xml b/pom.xml
index 4118d2fc..67074597 100644
--- a/pom.xml
+++ b/pom.xml
@@ -93,6 +93,7 @@
spring-cloud-kubernetes-discovery
spring-cloud-kubernetes-core
spring-cloud-starter-kubernetes
+ spring-cloud-kubernetes-ribbon
@@ -103,22 +104,39 @@
spring-cloud-kubernetes-core
${project.version}
+
io.fabric8
spring-cloud-kubernetes-discovery
${project.version}
+
+ io.fabric8
+ spring-cloud-kubernetes-ribbon
+ ${project.version}
+
+
io.fabric8
kubernetes-client
${kubernetes-client.version}
+
+
+ org.springframework.cloud
+ spring-cloud-netflix-dependencies
+ ${spring-cloud-netflix.version}
+ import
+ pom
+
+
org.springframework.boot
spring-boot-actuator
${spring-boot.version}
+
org.springframework.boot
spring-boot-autoconfigure
diff --git a/spring-cloud-kubernetes-ribbon/pom.xml b/spring-cloud-kubernetes-ribbon/pom.xml
new file mode 100644
index 00000000..563d032c
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/pom.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+ spring-cloud-kubernetes-project
+ io.fabric8
+ 0.0.2-SNAPSHOT
+
+ 4.0.0
+
+ io.fabric8
+ spring-cloud-kubernetes-ribbon
+ Fabric8 :: Spring Cloud Kubernetes :: Ribbon
+
+
+
+
+ io.fabric8
+ spring-cloud-kubernetes-discovery
+ ${project.version}
+
+
+
+ org.springframework.boot
+ spring-boot-autoconfigure
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-commons
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-context
+ true
+
+
+
+ org.springframework.cloud
+ spring-cloud-netflix-core
+ true
+
+
+
+ com.netflix.archaius
+ archaius-core
+ true
+
+
+
+ com.netflix.ribbon
+ ribbon
+ true
+
+
+
+ com.netflix.ribbon
+ ribbon-core
+ true
+
+
+
+ com.netflix.ribbon
+ ribbon-httpclient
+ true
+
+
+
+ com.netflix.ribbon
+ ribbon-loadbalancer
+ true
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesConfigKey.java b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesConfigKey.java
new file mode 100644
index 00000000..e2dd5f1a
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesConfigKey.java
@@ -0,0 +1,116 @@
+/*
+ * 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.ribbon;
+
+import com.google.common.reflect.TypeToken;
+import com.netflix.client.config.IClientConfigKey;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.HashSet;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+public abstract class KubernetesConfigKey implements IClientConfigKey {
+
+ public static final IClientConfigKey Namespace = new KubernetesConfigKey("KubernetesNamespace"){};
+ public static final IClientConfigKey PortName = new KubernetesConfigKey("PortName"){};
+
+ private static final Set keys = new HashSet();
+
+ static {
+ for (Field f: KubernetesConfigKey.class.getDeclaredFields()) {
+ if (Modifier.isStatic(f.getModifiers()) //&& Modifier.isPublic(f.getModifiers())
+ && IClientConfigKey.class.isAssignableFrom(f.getType())) {
+ try {
+ keys.add((IClientConfigKey) f.get(null));
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ }
+
+ /**
+ * @deprecated see {@link #keys()}
+ */
+ @Deprecated
+ public static IClientConfigKey[] values() {
+ return keys().toArray(new IClientConfigKey[0]);
+ }
+
+ /**
+ * return all the public static keys defined in this class
+ */
+ public static Set keys() {
+ return keys;
+ }
+
+ public static IClientConfigKey valueOf(final String name) {
+ for (IClientConfigKey key: keys()) {
+ if (key.key().equals(name)) {
+ return key;
+ }
+ }
+ return new IClientConfigKey() {
+ @Override
+ public String key() {
+ return name;
+ }
+
+ @Override
+ public Class type() {
+ return String.class;
+ }
+ };
+ }
+
+ private final String configKey;
+ private final Class type;
+
+ @SuppressWarnings("unchecked")
+ protected KubernetesConfigKey(String configKey) {
+ this.configKey = configKey;
+ Type superclass = getClass().getGenericSuperclass();
+ checkArgument(superclass instanceof ParameterizedType,
+ "%s isn't parameterized", superclass);
+ Type runtimeType = ((ParameterizedType) superclass).getActualTypeArguments()[0];
+ type = (Class) TypeToken.of(runtimeType).getRawType();
+ }
+
+ @Override
+ public Class type() {
+ return type;
+ }
+
+ /* (non-Javadoc)
+ * @see com.netflix.niws.client.ClientConfig#key()
+ */
+ @Override
+ public String key() {
+ return configKey;
+ }
+
+ @Override
+ public String toString() {
+ return configKey;
+ }
+}
diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java
new file mode 100644
index 00000000..0fe21860
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesRibbonClientConfiguration.java
@@ -0,0 +1,56 @@
+/*
+ * 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.ribbon;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.config.ConfigurationManager;
+import com.netflix.loadbalancer.IPing;
+import com.netflix.loadbalancer.Server;
+import com.netflix.loadbalancer.ServerList;
+import com.netflix.loadbalancer.ServerListFilter;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.spring.cloud.discovery.KubernetesDiscoveryProperties;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+
+import com.netflix.config.DynamicPropertyFactory;
+import com.netflix.config.DynamicStringProperty;
+
+import static com.netflix.client.config.CommonClientConfigKey.DeploymentContextBasedVipAddresses;
+import static com.netflix.client.config.CommonClientConfigKey.EnableZoneAffinity;
+
+@Configuration
+public class KubernetesRibbonClientConfiguration {
+
+ public KubernetesRibbonClientConfiguration() {
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public ServerList> ribbonServerList(KubernetesClient client, IClientConfig config) {
+ KubernetesServerList serverList = new KubernetesServerList(client);
+ serverList.initWithNiwsConfig(config);
+ return serverList;
+ }
+
+}
diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesServerList.java b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesServerList.java
new file mode 100644
index 00000000..67176972
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/KubernetesServerList.java
@@ -0,0 +1,100 @@
+/*
+ * 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.ribbon;
+
+import com.netflix.client.config.IClientConfig;
+import com.netflix.loadbalancer.AbstractServerList;
+import com.netflix.loadbalancer.Server;
+import com.netflix.loadbalancer.ServerList;
+import io.fabric8.kubernetes.api.model.EndpointAddress;
+import io.fabric8.kubernetes.api.model.EndpointPort;
+import io.fabric8.kubernetes.api.model.EndpointSubset;
+import io.fabric8.kubernetes.api.model.Endpoints;
+import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.utils.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class KubernetesServerList extends AbstractServerList implements ServerList {
+
+ private static final int FIRST = 0;
+ private static final Logger LOG = LoggerFactory.getLogger(KubernetesServerList.class);
+
+ private final KubernetesClient client;
+
+ private String serviceId;
+
+ private String namespace;
+ private String portName;
+
+
+ public KubernetesServerList(KubernetesClient client) {
+ this.client = client;
+ }
+
+ public void initWithNiwsConfig(IClientConfig clientConfig) {
+ this.serviceId = clientConfig.getClientName();
+ this.namespace = clientConfig.getPropertyAsString(KubernetesConfigKey.Namespace, client.getNamespace());
+ this.portName = clientConfig.getPropertyAsString(KubernetesConfigKey.PortName, null);
+ }
+
+ public List getInitialListOfServers() {
+ return Collections.emptyList();
+ }
+
+ public List getUpdatedListOfServers() {
+ Endpoints endpoints = namespace != null
+ ? client.endpoints().inNamespace(namespace).withName(serviceId).get()
+ : client.endpoints().withName(serviceId).get();
+
+ List result = new ArrayList();
+ if (endpoints != null) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found [" + endpoints.getSubsets().size() + "] endpoints in namespace [" +
+ namespace + "] for name [" + serviceId + "] and portName [" + portName + "]");
+ }
+ for (EndpointSubset subset : endpoints.getSubsets()) {
+
+ if (subset.getPorts().size() == 1) {
+ EndpointPort port = subset.getPorts().get(FIRST);
+ for (EndpointAddress address : subset.getAddresses()) {
+ result.add(new Server(address.getIp(), port.getPort()));
+ }
+ } else {
+ for (EndpointPort port : subset.getPorts()) {
+ if (Utils.isNullOrEmpty(portName) || portName.endsWith(port.getName())) {
+ for (EndpointAddress address : subset.getAddresses()) {
+ result.add(new Server(address.getIp(), port.getPort()));
+ }
+ }
+ }
+ }
+ }
+ } else {
+ LOG.warn("Did not find any endpoints in ribbon in namespace [" + namespace + "] for name [" +
+ serviceId + "] and portName [" + portName + "]");
+ }
+ return result;
+ }
+}
diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/RibbonConfigurationProperties.java b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/RibbonConfigurationProperties.java
new file mode 100644
index 00000000..b431c06f
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/RibbonConfigurationProperties.java
@@ -0,0 +1,32 @@
+/*
+ * 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.ribbon;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import java.util.Map;
+
+@ConfigurationProperties("ribbon")
+public class RibbonConfigurationProperties {
+
+ private Map overrides;
+
+ static class Override {
+
+ }
+}
diff --git a/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java
new file mode 100644
index 00000000..be2a0038
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/src/main/java/io/fabric8/spring/cloud/kubernetes/ribbon/RibbonKubernetesAutoConfiguration.java
@@ -0,0 +1,36 @@
+/*
+ * 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.ribbon;
+
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
+import org.springframework.cloud.netflix.ribbon.RibbonClients;
+import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties
+@ConditionalOnBean(SpringClientFactory.class)
+@ConditionalOnProperty(value = "spring.cloud.kubernetes.ribbon.enabled", matchIfMissing = true)
+@AutoConfigureAfter(RibbonAutoConfiguration.class)
+@RibbonClients(defaultConfiguration = KubernetesRibbonClientConfiguration.class)
+public class RibbonKubernetesAutoConfiguration {
+}
diff --git a/spring-cloud-kubernetes-ribbon/src/main/resources/META-INF/spring.factories b/spring-cloud-kubernetes-ribbon/src/main/resources/META-INF/spring.factories
new file mode 100644
index 00000000..c93cffa8
--- /dev/null
+++ b/spring-cloud-kubernetes-ribbon/src/main/resources/META-INF/spring.factories
@@ -0,0 +1,2 @@
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+io.fabric8.spring.cloud.kubernetes.ribbon.RibbonKubernetesAutoConfiguration
\ No newline at end of file
diff --git a/spring-cloud-starter-kubernetes/pom.xml b/spring-cloud-starter-kubernetes/pom.xml
index 8c10c9ae..487606bd 100644
--- a/spring-cloud-starter-kubernetes/pom.xml
+++ b/spring-cloud-starter-kubernetes/pom.xml
@@ -39,6 +39,11 @@
io.fabric8
spring-cloud-kubernetes-discovery
+
+
+ io.fabric8
+ spring-cloud-kubernetes-ribbon
+
\ No newline at end of file