diff --git a/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceConnector.java b/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceConnector.java new file mode 100644 index 0000000..9f9f1a9 --- /dev/null +++ b/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceConnector.java @@ -0,0 +1,75 @@ +package org.springframework.cloud.pcf.configserver; + +import org.springframework.cloud.Cloud; +import org.springframework.cloud.CloudFactory; +import org.springframework.cloud.service.ServiceInfo; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.MapPropertySource; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Method; +import java.util.Collections; + +/** + * Connector to Config Server service + * + * @author Chris Schaefer + */ +@Configuration +public class ConfigServerServiceConnector implements ApplicationListener, Ordered { + /** + * TODO: + * Bind ApplicationListener to ApplicationEnvironmentPreparedEvent, remove reflection + * and add test after repo migration in which we will have a direct dependency on boot. + */ + + private static final String PROPERTY_SOURCE_NAME = "vcapConfigServerUri"; + private static final String EVENT_ENVIRONMENT_METHOD_NAME = "getEnvironment"; + private static final String SPRING_CLOUD_CONFIG_URI = "spring.cloud.config.uri"; + private static final String EVENT_CLASS_NAME = "org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent"; + + private Cloud cloud; + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if(!supports(event.getClass().getName()) || cloud != null) { + return; + } + + cloud = new CloudFactory().getCloud(); + + for(ServiceInfo serviceInfo : cloud.getServiceInfos()) { + if(serviceInfo instanceof ConfigServerServiceInfo) { + String uri = ((ConfigServerServiceInfo) serviceInfo).getUri(); + + MapPropertySource mapPropertySource = new MapPropertySource(PROPERTY_SOURCE_NAME, + Collections.singletonMap(SPRING_CLOUD_CONFIG_URI, uri)); + + getEnvironment(event).getPropertySources().addFirst(mapPropertySource); + } + } + } + + private boolean supports(String className) { + return EVENT_CLASS_NAME.equals(className); + } + + private ConfigurableEnvironment getEnvironment(ApplicationEvent event) { + Method method = ReflectionUtils.findMethod(event.getClass(), EVENT_ENVIRONMENT_METHOD_NAME); + + try { + return (ConfigurableEnvironment) method.invoke(event); + } catch (Exception e) { + throw new RuntimeException("Error obtaining Environment from event", e); + } + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE + 4; + } +} diff --git a/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfo.java b/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfo.java new file mode 100644 index 0000000..f2c0d2d --- /dev/null +++ b/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfo.java @@ -0,0 +1,14 @@ +package org.springframework.cloud.pcf.configserver; + +import org.springframework.cloud.service.UriBasedServiceInfo; + +/** + * Service info to access Config Server services + * + * @author Chris Schaefer + */ +public class ConfigServerServiceInfo extends UriBasedServiceInfo { + public ConfigServerServiceInfo(String id, String uriString) { + super(id, uriString); + } +} diff --git a/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfoCreator.java b/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfoCreator.java new file mode 100644 index 0000000..1d8d1f9 --- /dev/null +++ b/spring-cloud-pcf-connector/src/main/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfoCreator.java @@ -0,0 +1,28 @@ +package org.springframework.cloud.pcf.configserver; + +import org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator; +import org.springframework.cloud.cloudfoundry.Tags; + +import java.util.Map; + +/** + * Service info creator for Config Server services + * + * @author Chris Schaefer + */ +public class ConfigServerServiceInfoCreator extends CloudFoundryServiceInfoCreator { + private static final String CREDENTIALS_ID_KEY = "name"; + private static final String CONFIG_SERVER_SERVICE_TAG_NAME = "configuration"; + + public ConfigServerServiceInfoCreator() { + super(new Tags(CONFIG_SERVER_SERVICE_TAG_NAME)); + } + + @Override + public ConfigServerServiceInfo createServiceInfo(Map serviceData) { + String id = (String) serviceData.get(CREDENTIALS_ID_KEY); + String uri = getUriFromCredentials(getCredentials(serviceData)); + + return new ConfigServerServiceInfo(id, uri); + } +} diff --git a/spring-cloud-pcf-connector/src/main/resources/META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator b/spring-cloud-pcf-connector/src/main/resources/META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator index 1486458..da1e07c 100644 --- a/spring-cloud-pcf-connector/src/main/resources/META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator +++ b/spring-cloud-pcf-connector/src/main/resources/META-INF/services/org.springframework.cloud.cloudfoundry.CloudFoundryServiceInfoCreator @@ -1,2 +1,3 @@ org.springframework.cloud.pcf.phd.PhdServiceInfoCreator org.springframework.cloud.pcf.eureka.EurekaServiceInfoCreator +org.springframework.cloud.pcf.configserver.ConfigServerServiceInfoCreator diff --git a/spring-cloud-pcf-connector/src/main/resources/META-INF/spring.factories b/spring-cloud-pcf-connector/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..155b64b --- /dev/null +++ b/spring-cloud-pcf-connector/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.context.ApplicationListener=\ +org.springframework.cloud.pcf.configserver.ConfigServerServiceConnector diff --git a/spring-cloud-pcf-connector/src/test/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfoCreatorTest.java b/spring-cloud-pcf-connector/src/test/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfoCreatorTest.java new file mode 100644 index 0000000..8ff29d3 --- /dev/null +++ b/spring-cloud-pcf-connector/src/test/java/org/springframework/cloud/pcf/configserver/ConfigServerServiceInfoCreatorTest.java @@ -0,0 +1,46 @@ +package org.springframework.cloud.pcf.configserver; + +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 Config Server services + * + * @author Chris Schaefer + */ +public class ConfigServerServiceInfoCreatorTest extends AbstractCloudFoundryConnectorTest { + private static final String CONFIG_SERVER_SERVICE_TAG_NAME = "myConfigServerService"; + private static final String VCAP_SERVICES_ENV_KEY = "VCAP_SERVICES"; + private static final String PAYLOAD_FILE_NAME = "test-config-server-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 configServerServiceCreationWithTags() { + when(mockEnvironment.getEnvValue(VCAP_SERVICES_ENV_KEY)) + .thenReturn(getServicesPayload(getConfigServerServicePayload(CONFIG_SERVER_SERVICE_TAG_NAME, + hostname, port, username, password))); + + List serviceInfos = testCloudConnector.getServiceInfos(); + assertServiceFoundOfType(serviceInfos, CONFIG_SERVER_SERVICE_TAG_NAME, ConfigServerServiceInfo.class); + } + + private String getConfigServerServicePayload(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; + } +} diff --git a/spring-cloud-pcf-connector/src/test/resources/org/springframework/cloud/pcf/configserver/test-config-server-info.json b/spring-cloud-pcf-connector/src/test/resources/org/springframework/cloud/pcf/configserver/test-config-server-info.json new file mode 100644 index 0000000..44dad0d --- /dev/null +++ b/spring-cloud-pcf-connector/src/test/resources/org/springframework/cloud/pcf/configserver/test-config-server-info.json @@ -0,0 +1,11 @@ +{ + "name":"$serviceName", + "label":"p-config", + "plan":"standard", + "tags":[ + "configuration" + ], + "credentials":{ + "uri":"http://$username:$password@$hostname:$port/" + } +}