PCF spring cloud connector for Eureka

This commit is contained in:
Chris Schaefer
2014-12-15 20:44:24 -05:00
parent 3f765c5515
commit c7bca2009d
10 changed files with 343 additions and 3 deletions

View File

@@ -35,6 +35,8 @@ ext {
junitVersion = "4.11"
mockitoVersion = "1.9.5"
eurekaClientVersion = "1.1.135"
hadoopCommonVersion = "2.2.0"
javadocLinks = [
'http://docs.oracle.com/javase/7/docs/api/',

View File

@@ -1,9 +1,11 @@
description = 'Spring-Cloud Support for Pivotal CF'
dependencies {
compile project(':spring-cloud-core')
compile project(':spring-cloud-cloudfoundry-connector')
compile project(':spring-cloud-spring-service-connector')
optional("org.apache.hadoop:hadoop-common:2.2.0")
optional("org.apache.hadoop:hadoop-common:$hadoopCommonVersion")
optional("com.netflix.eureka:eureka-client:$eurekaClientVersion")
testCompile project(path: ':spring-cloud-cloudfoundry-connector', configuration: 'tests')
}

View File

@@ -0,0 +1,191 @@
package org.springframework.cloud.pcf.eureka;
import com.netflix.discovery.EurekaClientConfig;
import org.springframework.cloud.service.AbstractServiceConnectorCreator;
import org.springframework.cloud.service.ServiceConnectorConfig;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.List;
/**
*
* Connector creator for Eureka client services
*
* @author Chris Schaefer
*/
public class EurekaClientConfigurationCreator extends AbstractServiceConnectorCreator<EurekaClientConfig, EurekaServiceInfo> {
@Override
public EurekaClientConfig create(EurekaServiceInfo serviceInfo, ServiceConnectorConfig serviceConnectorConfig) {
return getEurekaClientConfig(serviceInfo);
}
protected EurekaClientConfig getEurekaClientConfig(EurekaServiceInfo serviceInfo) {
return new DefaultPcfEurekaClientConfig(serviceInfo.getUri());
}
private static final class DefaultPcfEurekaClientConfig implements EurekaClientConfig {
private static final int MINUTES = 60;
private static final String REGION = "default";
private static final String DEFAULT_ZONE = "defaultZone";
private static final String EUREKA_API_PREFIX = "/eureka/";
private final String uri;
public DefaultPcfEurekaClientConfig(String uri) {
this.uri = uri + EUREKA_API_PREFIX;
}
@Override
public int getRegistryFetchIntervalSeconds() {
return 5;
}
@Override
public int getInstanceInfoReplicationIntervalSeconds() {
return 30;
}
@Override
public int getInitialInstanceInfoReplicationIntervalSeconds() {
return 40;
}
@Override
public int getEurekaServiceUrlPollIntervalSeconds() {
return 5 * MINUTES;
}
@Override
public String getProxyHost() {
return null;
}
@Override
public String getProxyPort() {
return null;
}
@Override
public boolean shouldGZipContent() {
return true;
}
@Override
public int getEurekaServerReadTimeoutSeconds() {
return 8;
}
@Override
public int getEurekaServerConnectTimeoutSeconds() {
return 5;
}
@Override
public String getBackupRegistryImpl() {
return null;
}
@Override
public int getEurekaServerTotalConnections() {
return 200;
}
@Override
public int getEurekaServerTotalConnectionsPerHost() {
return 50;
}
@Override
public String getEurekaServerURLContext() {
return null;
}
@Override
public String getEurekaServerPort() {
return null;
}
@Override
public String getEurekaServerDNSName() {
return null;
}
@Override
public boolean shouldUseDnsForFetchingServiceUrls() {
return false;
}
@Override
public boolean shouldRegisterWithEureka() {
return true;
}
@Override
public boolean shouldPreferSameZoneEureka() {
return true;
}
@Override
public boolean shouldLogDeltaDiff() {
return false;
}
@Override
public boolean shouldDisableDelta() {
return false;
}
@Nullable
@Override
public String fetchRegistryForRemoteRegions() {
return null;
}
@Override
public String getRegion() {
return REGION;
}
@Override
public String[] getAvailabilityZones(String region) {
return new String[] { DEFAULT_ZONE };
}
@Override
public List<String> getEurekaServerServiceUrls(String myZone) {
return Arrays.asList(uri);
}
@Override
public boolean shouldFilterOnlyUpInstances() {
return true;
}
@Override
public int getEurekaConnectionIdleTimeoutSeconds() {
return 30;
}
@Override
public boolean shouldFetchRegistry() {
return true;
}
@Nullable
@Override
public String getRegistryRefreshSingleVipAddress() {
return null;
}
@Override
public int getHeartbeatExecutorThreadPoolSize() {
return 2;
}
@Override
public int getCacheRefreshExecutorThreadPoolSize() {
return 2;
}
}
}

View File

@@ -0,0 +1,16 @@
package org.springframework.cloud.pcf.eureka;
import org.springframework.cloud.service.ServiceInfo;
import org.springframework.cloud.service.UriBasedServiceInfo;
/**
* Information to access Eureka services
*
* @author Chris Schaefer
*/
@ServiceInfo.ServiceLabel("eureka")
public class EurekaServiceInfo extends UriBasedServiceInfo {
public EurekaServiceInfo(String id, String uriString) {
super(id, uriString);
}
}

View File

@@ -0,0 +1,29 @@
package org.springframework.cloud.pcf.eureka;
import org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator;
import org.springframework.cloud.cloudfoundry.Tags;
import java.util.Map;
/**
*
* Service info creator for Eureka services
*
* @author Chris Schaefer
*/
public class EurekaServiceInfoCreator extends CloudFoundryServiceInfoCreator<EurekaServiceInfo> {
private static final String CREDENTIALS_ID_KEY = "name";
private static final String EUREKA_SERVICE_TAG_NAME = "eureka";
public EurekaServiceInfoCreator() {
super(new Tags(EUREKA_SERVICE_TAG_NAME));
}
@Override
public EurekaServiceInfo createServiceInfo(Map<String, Object> serviceData) {
String id = (String) serviceData.get(CREDENTIALS_ID_KEY);
String uri = getUriFromCredentials(getCredentials(serviceData));
return new EurekaServiceInfo(id, uri);
}
}

View File

@@ -1 +1,2 @@
org.springframework.cloud.pcf.phd.PhdServiceInfoCreator
org.springframework.cloud.pcf.eureka.EurekaServiceInfoCreator

View File

@@ -1,2 +1,3 @@
org.springframework.cloud.pcf.hadoop.HadoopConfigurationCreator
org.springframework.cloud.pcf.gemfire.GemfireXDDataSourceCreator
org.springframework.cloud.pcf.gemfire.GemfireXDDataSourceCreator
org.springframework.cloud.pcf.eureka.EurekaClientConfigurationCreator

View File

@@ -0,0 +1,42 @@
package org.springframework.cloud.pcf.eureka;
import com.netflix.discovery.EurekaClientConfig;
import org.junit.Test;
import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* Test cases around the Eureka client configuration creator
*
* @author Chris Schaefer
*/
public class EurekaClientConfigurationCreatorTest {
private static final String REGION = "default";
private static final String SERVICE_INFO_ID = "id";
private static final int REGISTRY_FETCH_INTERVAL_SECS = 5;
private static final String AVAILABLITY_ZONE = "defaultZone";
private static final String URI = "http://user:pass@192.168.23.4:1234";
private static final String EUREKA_API_PREFIX = "/eureka/";
private EurekaClientConfigurationCreator eurekaClientConfigurationCreator = new EurekaClientConfigurationCreator();
@Test
public void testClientConfiguration() {
EurekaServiceInfo eurekaServiceInfo = new EurekaServiceInfo(SERVICE_INFO_ID, URI);
EurekaClientConfig eurekaClientConfig = eurekaClientConfigurationCreator.create(eurekaServiceInfo, null);
List<String> serviceUrls = eurekaClientConfig.getEurekaServerServiceUrls(null);
assertEquals(1, serviceUrls.size());
assertEquals(URI + EUREKA_API_PREFIX, serviceUrls.get(0));
assertEquals(REGION, eurekaClientConfig.getRegion());
assertEquals(REGISTRY_FETCH_INTERVAL_SECS, eurekaClientConfig.getRegistryFetchIntervalSeconds());
String[] availablityZones = eurekaClientConfig.getAvailabilityZones(null);
assertEquals(1, availablityZones.length);
assertEquals(AVAILABLITY_ZONE, availablityZones[0]);
}
}

View File

@@ -0,0 +1,45 @@
package org.springframework.cloud.pcf.eureka;
import org.junit.Test;
import org.springframework.cloud.cloudfoundry.AbstractCloudFoundryConnectorTest;
import org.springframework.cloud.service.ServiceInfo;
import java.util.List;
import static org.mockito.Mockito.when;
/**
* Connector tests for Eureka services
*
* @author Chris Schaefer
*/
public class EurekaServiceInfoCreatorTest extends AbstractCloudFoundryConnectorTest {
private static final String EUREKA_SERVICE_TAG_NAME = "myEurekaInstance";
private static final String VCAP_SERVICES_ENV_KEY = "VCAP_SERVICES";
private static final String PAYLOAD_FILE_NAME = "test-eureka-info.json";
private static final String PAYLOAD_TEMPLATE_SERVICE_NAME = "$serviceName";
private static final String PAYLOAD_TEMPLATE_HOSTNAME = "$hostname";
private static final String PAYLOAD_TEMPLATE_PORT = "$port";
private static final String PAYLOAD_TEMPLATE_USER = "$user";
private static final String PAYLOAD_TEMPLATE_PASS = "$pass";
@Test
public void eurekaServiceCreationWithTags() {
when(mockEnvironment.getEnvValue(VCAP_SERVICES_ENV_KEY))
.thenReturn(getServicesPayload(getEurekaServicePayload(EUREKA_SERVICE_TAG_NAME, hostname, port, username, password)));
List<ServiceInfo> serviceInfos = testCloudConnector.getServiceInfos();
assertServiceFoundOfType(serviceInfos, EUREKA_SERVICE_TAG_NAME, EurekaServiceInfo.class);
}
private String getEurekaServicePayload(String serviceName, String hostname, int port, String user, String password) {
String payload = readTestDataFile(PAYLOAD_FILE_NAME);
payload = payload.replace(PAYLOAD_TEMPLATE_SERVICE_NAME, serviceName);
payload = payload.replace(PAYLOAD_TEMPLATE_HOSTNAME, hostname);
payload = payload.replace(PAYLOAD_TEMPLATE_PORT, Integer.toString(port));
payload = payload.replace(PAYLOAD_TEMPLATE_USER, user);
payload = payload.replace(PAYLOAD_TEMPLATE_PASS, password);
return payload;
}
}

View File

@@ -0,0 +1,11 @@
{
"name":"$serviceName",
"label":"p-eureka",
"plan":"standard",
"tags":[
"eureka"
],
"credentials":{
"uri":"http://$username:$password@$hostname:$port/"
}
}