Bumping versions

This commit is contained in:
buildmaster
2020-09-17 17:52:36 +00:00
parent dad59dea10
commit 2e2ff80e07
25 changed files with 255 additions and 447 deletions

View File

@@ -47,12 +47,9 @@ import org.springframework.context.annotation.Lazy;
* @author Scott Frederick * @author Scott Frederick
*/ */
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.cloud.cloudfoundry", @ConditionalOnProperty(prefix = "spring.cloud.cloudfoundry", name = { "username", "password" })
name = { "username", "password" }) @ConditionalOnClass(name = { "reactor.core.publisher.Flux", "org.cloudfoundry.operations.DefaultCloudFoundryOperations",
@ConditionalOnClass(name = { "reactor.core.publisher.Flux", "org.cloudfoundry.reactor.client.ReactorCloudFoundryClient", "org.reactivestreams.Publisher" })
"org.cloudfoundry.operations.DefaultCloudFoundryOperations",
"org.cloudfoundry.reactor.client.ReactorCloudFoundryClient",
"org.reactivestreams.Publisher" })
@EnableConfigurationProperties(CloudFoundryProperties.class) @EnableConfigurationProperties(CloudFoundryProperties.class)
public class CloudFoundryClientAutoConfiguration { public class CloudFoundryClientAutoConfiguration {
@@ -65,59 +62,50 @@ public class CloudFoundryClientAutoConfiguration {
@Bean @Bean
@Lazy @Lazy
@ConditionalOnMissingBean @ConditionalOnMissingBean
public CloudFoundryService cloudFoundryService( public CloudFoundryService cloudFoundryService(CloudFoundryOperations cloudFoundryOperations) {
CloudFoundryOperations cloudFoundryOperations) {
return new CloudFoundryService(cloudFoundryOperations); return new CloudFoundryService(cloudFoundryOperations);
} }
@Bean @Bean
@Lazy @Lazy
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DefaultCloudFoundryOperations cloudFoundryOperations( public DefaultCloudFoundryOperations cloudFoundryOperations(CloudFoundryClient cloudFoundryClient,
CloudFoundryClient cloudFoundryClient, DopplerClient dopplerClient, DopplerClient dopplerClient, RoutingClient routingClient, UaaClient uaaClient) {
RoutingClient routingClient, UaaClient uaaClient) {
String organization = this.cloudFoundryProperties.getOrg(); String organization = this.cloudFoundryProperties.getOrg();
String space = this.cloudFoundryProperties.getSpace(); String space = this.cloudFoundryProperties.getSpace();
return DefaultCloudFoundryOperations.builder() return DefaultCloudFoundryOperations.builder().cloudFoundryClient(cloudFoundryClient)
.cloudFoundryClient(cloudFoundryClient).dopplerClient(dopplerClient) .dopplerClient(dopplerClient).routingClient(routingClient).uaaClient(uaaClient)
.routingClient(routingClient).uaaClient(uaaClient)
.organization(organization).space(space).build(); .organization(organization).space(space).build();
} }
@Bean @Bean
@Lazy @Lazy
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ReactorCloudFoundryClient cloudFoundryClient( public ReactorCloudFoundryClient cloudFoundryClient(ConnectionContext connectionContext,
ConnectionContext connectionContext, TokenProvider tokenProvider) { TokenProvider tokenProvider) {
return ReactorCloudFoundryClient.builder().connectionContext(connectionContext) return ReactorCloudFoundryClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider)
.tokenProvider(tokenProvider).build(); .build();
} }
@Bean @Bean
@Lazy @Lazy
@ConditionalOnMissingBean @ConditionalOnMissingBean
public DopplerClient dopplerClient(ConnectionContext connectionContext, public DopplerClient dopplerClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
TokenProvider tokenProvider) { return ReactorDopplerClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build();
return ReactorDopplerClient.builder().connectionContext(connectionContext)
.tokenProvider(tokenProvider).build();
} }
@Bean @Bean
@Lazy @Lazy
@ConditionalOnMissingBean @ConditionalOnMissingBean
public RoutingClient routingClient(ConnectionContext connectionContext, public RoutingClient routingClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
TokenProvider tokenProvider) { return ReactorRoutingClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build();
return ReactorRoutingClient.builder().connectionContext(connectionContext)
.tokenProvider(tokenProvider).build();
} }
@Bean @Bean
@Lazy @Lazy
@ConditionalOnMissingBean @ConditionalOnMissingBean
public ReactorUaaClient uaaClient(ConnectionContext connectionContext, public ReactorUaaClient uaaClient(ConnectionContext connectionContext, TokenProvider tokenProvider) {
TokenProvider tokenProvider) { return ReactorUaaClient.builder().connectionContext(connectionContext).tokenProvider(tokenProvider).build();
return ReactorUaaClient.builder().connectionContext(connectionContext)
.tokenProvider(tokenProvider).build();
} }
@Bean @Bean
@@ -127,8 +115,7 @@ public class CloudFoundryClientAutoConfiguration {
String apiHost = this.cloudFoundryProperties.getUrl(); String apiHost = this.cloudFoundryProperties.getUrl();
Boolean skipSslValidation = this.cloudFoundryProperties.isSkipSslValidation(); Boolean skipSslValidation = this.cloudFoundryProperties.isSkipSslValidation();
return DefaultConnectionContext.builder().apiHost(apiHost) return DefaultConnectionContext.builder().apiHost(apiHost).skipSslValidation(skipSslValidation).build();
.skipSslValidation(skipSslValidation).build();
} }
@Bean @Bean
@@ -137,8 +124,7 @@ public class CloudFoundryClientAutoConfiguration {
public PasswordGrantTokenProvider tokenProvider() { public PasswordGrantTokenProvider tokenProvider() {
String username = this.cloudFoundryProperties.getUsername(); String username = this.cloudFoundryProperties.getUsername();
String password = this.cloudFoundryProperties.getPassword(); String password = this.cloudFoundryProperties.getPassword();
return PasswordGrantTokenProvider.builder().password(password).username(username) return PasswordGrantTokenProvider.builder().password(password).username(username).build();
.build();
} }
} }

View File

@@ -146,8 +146,7 @@ public class CloudFoundryProperties implements InitializingBean {
vals.put("url", getUrl()); vals.put("url", getUrl());
vals.put("username", getUsername()); vals.put("username", getUsername());
vals.put("password", getPassword()); vals.put("password", getPassword());
vals.forEach((key, value) -> Assert.hasText(value, vals.forEach((key, value) -> Assert.hasText(value, String.format("'%s' must be provided", key)));
String.format("'%s' must be provided", key)));
} }
} }

View File

@@ -37,19 +37,14 @@ public class CloudFoundryService {
this.cloudFoundryOperations = cloudFoundryOperations; this.cloudFoundryOperations = cloudFoundryOperations;
} }
public Flux<Tuple2<ApplicationDetail, InstanceDetail>> getApplicationInstances( public Flux<Tuple2<ApplicationDetail, InstanceDetail>> getApplicationInstances(String serviceId) {
String serviceId) { GetApplicationRequest applicationRequest = GetApplicationRequest.builder().name(serviceId).build();
GetApplicationRequest applicationRequest = GetApplicationRequest.builder() return this.cloudFoundryOperations.applications().get(applicationRequest).flatMapMany(applicationDetail -> {
.name(serviceId).build(); Flux<InstanceDetail> ids = Flux.fromStream(applicationDetail.getInstanceDetails().stream())
return this.cloudFoundryOperations.applications().get(applicationRequest) .filter(id -> id.getState().equalsIgnoreCase("RUNNING"));
.flatMapMany(applicationDetail -> { Flux<ApplicationDetail> generate = Flux.generate(sink -> sink.next(applicationDetail));
Flux<InstanceDetail> ids = Flux return generate.zipWith(ids);
.fromStream(applicationDetail.getInstanceDetails().stream()) });
.filter(id -> id.getState().equalsIgnoreCase("RUNNING"));
Flux<ApplicationDetail> generate = Flux
.generate(sink -> sink.next(applicationDetail));
return generate.zipWith(ids);
});
} }
} }

View File

@@ -36,12 +36,11 @@ import static org.assertj.core.api.Assertions.assertThat;
public class CloudFoundryClientAutoConfigurationTest { public class CloudFoundryClientAutoConfigurationTest {
private final static String[] SPRING_CLOUD_PROPERTIES = { private final static String[] SPRING_CLOUD_PROPERTIES = { "spring.cloud.cloudfoundry.username",
"spring.cloud.cloudfoundry.username", "spring.cloud.cloudfoundry.password", }; "spring.cloud.cloudfoundry.password", };
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration( .withConfiguration(AutoConfigurations.of(CloudFoundryClientAutoConfiguration.class));
AutoConfigurations.of(CloudFoundryClientAutoConfiguration.class));
private static boolean requiredPropertiesSet() { private static boolean requiredPropertiesSet() {
for (String k : SPRING_CLOUD_PROPERTIES) { for (String k : SPRING_CLOUD_PROPERTIES) {
@@ -59,13 +58,11 @@ public class CloudFoundryClientAutoConfigurationTest {
@Test @Test
public void autoConfiguresBeansWithAllProperties() { public void autoConfiguresBeansWithAllProperties() {
this.contextRunner.withPropertyValues("spring.cloud.cloudfoundry.username=user", this.contextRunner.withPropertyValues("spring.cloud.cloudfoundry.username=user",
"spring.cloud.cloudfoundry.password=secret", "spring.cloud.cloudfoundry.password=secret", "spring.cloud.cloudfoundry.org=myorg",
"spring.cloud.cloudfoundry.org=myorg",
"spring.cloud.cloudfoundry.space=myspace").run((context) -> { "spring.cloud.cloudfoundry.space=myspace").run((context) -> {
assertCloudFoundryClientBeansPresent(context); assertCloudFoundryClientBeansPresent(context);
DefaultCloudFoundryOperations operations = context DefaultCloudFoundryOperations operations = context.getBean(DefaultCloudFoundryOperations.class);
.getBean(DefaultCloudFoundryOperations.class);
assertThat(operations.getOrganization()).isEqualTo("myorg"); assertThat(operations.getOrganization()).isEqualTo("myorg");
assertThat(operations.getSpace()).isEqualTo("myspace"); assertThat(operations.getSpace()).isEqualTo("myspace");
}); });
@@ -77,8 +74,7 @@ public class CloudFoundryClientAutoConfigurationTest {
"spring.cloud.cloudfoundry.password=secret").run((context) -> { "spring.cloud.cloudfoundry.password=secret").run((context) -> {
assertCloudFoundryClientBeansPresent(context); assertCloudFoundryClientBeansPresent(context);
DefaultCloudFoundryOperations operations = context DefaultCloudFoundryOperations operations = context.getBean(DefaultCloudFoundryOperations.class);
.getBean(DefaultCloudFoundryOperations.class);
assertThat(operations.getOrganization()).isNullOrEmpty(); assertThat(operations.getOrganization()).isNullOrEmpty();
assertThat(operations.getSpace()).isNullOrEmpty(); assertThat(operations.getSpace()).isNullOrEmpty();
}); });
@@ -90,8 +86,7 @@ public class CloudFoundryClientAutoConfigurationTest {
this.contextRunner.run((context) -> { this.contextRunner.run((context) -> {
assertCloudFoundryClientBeansPresent(context); assertCloudFoundryClientBeansPresent(context);
CloudFoundryOperations operations = context CloudFoundryOperations operations = context.getBean(CloudFoundryOperations.class);
.getBean(CloudFoundryOperations.class);
OrganizationSummary summary = operations.organizations().list().blockFirst(); OrganizationSummary summary = operations.organizations().list().blockFirst();
@@ -101,8 +96,7 @@ public class CloudFoundryClientAutoConfigurationTest {
}); });
} }
private void assertCloudFoundryClientBeansPresent( private void assertCloudFoundryClientBeansPresent(AssertableApplicationContext context) {
AssertableApplicationContext context) {
assertThat(context).hasSingleBean(ReactorCloudFoundryClient.class); assertThat(context).hasSingleBean(ReactorCloudFoundryClient.class);
assertThat(context).hasSingleBean(DefaultCloudFoundryOperations.class); assertThat(context).hasSingleBean(DefaultCloudFoundryOperations.class);
assertThat(context).hasSingleBean(DefaultConnectionContext.class); assertThat(context).hasSingleBean(DefaultConnectionContext.class);

View File

@@ -43,8 +43,7 @@ public class CloudFoundryAppServiceDiscoveryClient extends CloudFoundryDiscovery
private static final String INTERNAL_DOMAIN = "apps.internal"; private static final String INTERNAL_DOMAIN = "apps.internal";
CloudFoundryAppServiceDiscoveryClient(CloudFoundryOperations cloudFoundryOperations, CloudFoundryAppServiceDiscoveryClient(CloudFoundryOperations cloudFoundryOperations, CloudFoundryService svc,
CloudFoundryService svc,
CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) { CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) {
super(cloudFoundryOperations, svc, cloudFoundryDiscoveryProperties); super(cloudFoundryOperations, svc, cloudFoundryDiscoveryProperties);
} }
@@ -56,23 +55,19 @@ public class CloudFoundryAppServiceDiscoveryClient extends CloudFoundryDiscovery
@Override @Override
public List<ServiceInstance> getInstances(String serviceId) { public List<ServiceInstance> getInstances(String serviceId) {
return getCloudFoundryService() return getCloudFoundryService().getApplicationInstances(serviceId)
.getApplicationInstances(serviceId).filter(tuple -> tuple.getT1() .filter(tuple -> tuple.getT1().getUrls().stream().anyMatch(this::isInternalDomain)).map(tuple -> {
.getUrls().stream().anyMatch(this::isInternalDomain))
.map(tuple -> {
ApplicationDetail applicationDetail = tuple.getT1(); ApplicationDetail applicationDetail = tuple.getT1();
InstanceDetail instanceDetail = tuple.getT2(); InstanceDetail instanceDetail = tuple.getT2();
String applicationId = applicationDetail.getId(); String applicationId = applicationDetail.getId();
String applicationIndex = instanceDetail.getIndex(); String applicationIndex = instanceDetail.getIndex();
String name = applicationDetail.getName(); String name = applicationDetail.getName();
String url = applicationDetail.getUrls().stream() String url = applicationDetail.getUrls().stream().filter(this::isInternalDomain).findFirst()
.filter(this::isInternalDomain).findFirst()
.map(x -> instanceDetail.getIndex() + "." + x).get(); .map(x -> instanceDetail.getIndex() + "." + x).get();
HashMap<String, String> metadata = new HashMap<>(); HashMap<String, String> metadata = new HashMap<>();
metadata.put("applicationId", applicationId); metadata.put("applicationId", applicationId);
metadata.put("instanceId", applicationIndex); metadata.put("instanceId", applicationIndex);
return (ServiceInstance) new DefaultServiceInstance(name, url, 8080, return (ServiceInstance) new DefaultServiceInstance(name, url, 8080, false, metadata);
false, metadata);
}).collectList().block(); }).collectList().block();
} }

View File

@@ -48,11 +48,10 @@ public class CloudFoundryDiscoveryClient implements DiscoveryClient {
private final CloudFoundryDiscoveryProperties properties; private final CloudFoundryDiscoveryProperties properties;
private final String description = "Cloud Foundry " + DiscoveryClient.class.getName() private final String description = "Cloud Foundry " + DiscoveryClient.class.getName() + " implementation";
+ " implementation";
CloudFoundryDiscoveryClient(CloudFoundryOperations cloudFoundryOperations, CloudFoundryDiscoveryClient(CloudFoundryOperations cloudFoundryOperations, CloudFoundryService svc,
CloudFoundryService svc, CloudFoundryDiscoveryProperties properties) { CloudFoundryDiscoveryProperties properties) {
this.cloudFoundryService = svc; this.cloudFoundryService = svc;
this.cloudFoundryOperations = cloudFoundryOperations; this.cloudFoundryOperations = cloudFoundryOperations;
this.properties = properties; this.properties = properties;
@@ -73,24 +72,22 @@ public class CloudFoundryDiscoveryClient implements DiscoveryClient {
String applicationIndex = instanceDetail.getIndex(); String applicationIndex = instanceDetail.getIndex();
String instanceId = applicationId + "." + applicationIndex; String instanceId = applicationId + "." + applicationIndex;
String name = applicationDetail.getName(); String name = applicationDetail.getName();
String url = applicationDetail.getUrls().size() > 0 String url = applicationDetail.getUrls().size() > 0 ? applicationDetail.getUrls().get(0) : null;
? applicationDetail.getUrls().get(0) : null;
boolean secure = (url + "").toLowerCase().startsWith("https"); boolean secure = (url + "").toLowerCase().startsWith("https");
HashMap<String, String> metadata = new HashMap<>(); HashMap<String, String> metadata = new HashMap<>();
metadata.put("applicationId", applicationId); metadata.put("applicationId", applicationId);
metadata.put("instanceId", applicationIndex); metadata.put("instanceId", applicationIndex);
return (ServiceInstance) new DefaultServiceInstance(instanceId, name, url, return (ServiceInstance) new DefaultServiceInstance(instanceId, name, url, secure ? 443 : 80, secure,
secure ? 443 : 80, secure, metadata); metadata);
}).collectList().blockOptional().orElse(new ArrayList<>()); }).collectList().blockOptional().orElse(new ArrayList<>());
} }
@Override @Override
public List<String> getServices() { public List<String> getServices() {
return this.cloudFoundryOperations.applications().list() return this.cloudFoundryOperations.applications().list().map(ApplicationSummary::getName).collectList()
.map(ApplicationSummary::getName).collectList().blockOptional() .blockOptional().orElse(new ArrayList<>());
.orElse(new ArrayList<>());
} }
@Override @Override

View File

@@ -45,39 +45,32 @@ public class CloudFoundryDiscoveryClientConfiguration {
@Bean @Bean
@ConditionalOnBean(CloudFoundryDiscoveryClient.class) @ConditionalOnBean(CloudFoundryDiscoveryClient.class)
public CloudFoundryHeartbeatSender cloudFoundryHeartbeatSender( public CloudFoundryHeartbeatSender cloudFoundryHeartbeatSender(CloudFoundryDiscoveryClient client) {
CloudFoundryDiscoveryClient client) {
return new CloudFoundryHeartbeatSender(client); return new CloudFoundryHeartbeatSender(client);
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", havingValue = "false",
havingValue = "false", matchIfMissing = true) matchIfMissing = true)
public static class CloudFoundryDiscoveryClientConfig { public static class CloudFoundryDiscoveryClientConfig {
@Bean @Bean
@ConditionalOnMissingBean(DiscoveryClient.class) @ConditionalOnMissingBean(DiscoveryClient.class)
public CloudFoundryDiscoveryClient cloudFoundryDiscoveryClient( public CloudFoundryDiscoveryClient cloudFoundryDiscoveryClient(CloudFoundryOperations cf,
CloudFoundryOperations cf, CloudFoundryService svc, CloudFoundryService svc, CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) {
CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) { return new CloudFoundryDiscoveryClient(cf, svc, cloudFoundryDiscoveryProperties);
return new CloudFoundryDiscoveryClient(cf, svc,
cloudFoundryDiscoveryProperties);
} }
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", havingValue = "true")
havingValue = "true")
public static class DnsBasedCloudFoundryDiscoveryClientConfig { public static class DnsBasedCloudFoundryDiscoveryClientConfig {
@Bean @Bean
@ConditionalOnProperty( @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-container-ip", havingValue = "true")
value = "spring.cloud.cloudfoundry.discovery.use-container-ip",
havingValue = "true")
@ConditionalOnMissingBean(DiscoveryClient.class) @ConditionalOnMissingBean(DiscoveryClient.class)
public SimpleDnsBasedDiscoveryClient discoveryClient( public SimpleDnsBasedDiscoveryClient discoveryClient(ObjectProvider<ServiceIdToHostnameConverter> provider,
ObjectProvider<ServiceIdToHostnameConverter> provider,
CloudFoundryDiscoveryProperties properties) { CloudFoundryDiscoveryProperties properties) {
ServiceIdToHostnameConverter converter = provider.getIfAvailable(); ServiceIdToHostnameConverter converter = provider.getIfAvailable();
return converter == null ? new SimpleDnsBasedDiscoveryClient(properties) return converter == null ? new SimpleDnsBasedDiscoveryClient(properties)
@@ -85,13 +78,11 @@ public class CloudFoundryDiscoveryClientConfiguration {
} }
@Bean @Bean
@ConditionalOnProperty( @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-container-ip", havingValue = "false",
value = "spring.cloud.cloudfoundry.discovery.use-container-ip", matchIfMissing = true)
havingValue = "false", matchIfMissing = true)
@ConditionalOnMissingBean(DiscoveryClient.class) @ConditionalOnMissingBean(DiscoveryClient.class)
public CloudFoundryAppServiceDiscoveryClient cloudFoundryDiscoveryClient( public CloudFoundryAppServiceDiscoveryClient cloudFoundryDiscoveryClient(CloudFoundryOperations cf,
CloudFoundryOperations cf, CloudFoundryService svc, CloudFoundryService svc, CloudFoundryDiscoveryProperties properties) {
CloudFoundryDiscoveryProperties properties) {
return new CloudFoundryAppServiceDiscoveryClient(cf, svc, properties); return new CloudFoundryAppServiceDiscoveryClient(cf, svc, properties);
} }

View File

@@ -42,8 +42,7 @@ public class CloudFoundryHeartbeatSender implements ApplicationEventPublisherAwa
this.client = client; this.client = client;
} }
@Scheduled( @Scheduled(fixedDelayString = "${spring.cloud.cloudfoundry.discovery.heartbeatFrequency:5000}")
fixedDelayString = "${spring.cloud.cloudfoundry.discovery.heartbeatFrequency:5000}")
public void poll() { public void poll() {
if (this.publisher != null) { if (this.publisher != null) {
List<String> services = this.client.getServices(); List<String> services = this.client.getServices();

View File

@@ -36,8 +36,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Inherited @Inherited
@ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.enabled", @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.enabled", matchIfMissing = true)
matchIfMissing = true)
public @interface ConditionalOnCloudFoundryDiscoveryEnabled { public @interface ConditionalOnCloudFoundryDiscoveryEnabled {
} }

View File

@@ -40,8 +40,7 @@ import org.springframework.cloud.client.discovery.DiscoveryClient;
*/ */
public class SimpleDnsBasedDiscoveryClient implements DiscoveryClient { public class SimpleDnsBasedDiscoveryClient implements DiscoveryClient {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory.getLogger(SimpleDnsBasedDiscoveryClient.class);
.getLogger(SimpleDnsBasedDiscoveryClient.class);
private final ServiceIdToHostnameConverter serviceIdToHostnameConverter; private final ServiceIdToHostnameConverter serviceIdToHostnameConverter;
@@ -67,8 +66,8 @@ public class SimpleDnsBasedDiscoveryClient implements DiscoveryClient {
InetAddress[] addresses = InetAddress.getAllByName(hostname); InetAddress[] addresses = InetAddress.getAllByName(hostname);
if (addresses != null) { if (addresses != null) {
for (InetAddress address : addresses) { for (InetAddress address : addresses) {
DefaultServiceInstance serviceInstance = new DefaultServiceInstance( DefaultServiceInstance serviceInstance = new DefaultServiceInstance(serviceId,
serviceId, address.getHostAddress(), 8080, false); address.getHostAddress(), 8080, false);
serviceInstances.add(serviceInstance); serviceInstances.add(serviceInstance);
} }
} }

View File

@@ -34,16 +34,14 @@ import org.springframework.cloud.cloudfoundry.discovery.CloudFoundryDiscoveryPro
* "https://www.cloudfoundry.org/blog/polyglot-service-discovery-container-networking-cloud-foundry/">Polyglot * "https://www.cloudfoundry.org/blog/polyglot-service-discovery-container-networking-cloud-foundry/">Polyglot
* Service Discovery for Container Networking in Cloud Foundry</a> * Service Discovery for Container Networking in Cloud Foundry</a>
*/ */
public class CloudFoundryAppServiceReactiveDiscoveryClient public class CloudFoundryAppServiceReactiveDiscoveryClient extends CloudFoundryNativeReactiveDiscoveryClient {
extends CloudFoundryNativeReactiveDiscoveryClient {
private static final String INTERNAL_DOMAIN = "apps.internal"; private static final String INTERNAL_DOMAIN = "apps.internal";
private final CloudFoundryService cloudFoundryService; private final CloudFoundryService cloudFoundryService;
CloudFoundryAppServiceReactiveDiscoveryClient( CloudFoundryAppServiceReactiveDiscoveryClient(CloudFoundryOperations cloudFoundryOperations,
CloudFoundryOperations cloudFoundryOperations, CloudFoundryService svc, CloudFoundryService svc, CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) {
CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) {
super(cloudFoundryOperations, svc, cloudFoundryDiscoveryProperties); super(cloudFoundryOperations, svc, cloudFoundryDiscoveryProperties);
this.cloudFoundryService = svc; this.cloudFoundryService = svc;
} }
@@ -56,8 +54,7 @@ public class CloudFoundryAppServiceReactiveDiscoveryClient
@Override @Override
public Flux<ServiceInstance> getInstances(String serviceId) { public Flux<ServiceInstance> getInstances(String serviceId) {
return cloudFoundryService.getApplicationInstances(serviceId) return cloudFoundryService.getApplicationInstances(serviceId)
.filter(tuple -> tuple.getT1().getUrls().stream() .filter(tuple -> tuple.getT1().getUrls().stream().anyMatch(this::isInternalDomain))
.anyMatch(this::isInternalDomain))
.map(this::mapApplicationInstanceToServiceInstance); .map(this::mapApplicationInstanceToServiceInstance);
} }

View File

@@ -37,8 +37,7 @@ import org.springframework.cloud.cloudfoundry.discovery.CloudFoundryDiscoveryPro
* *
* @author Tim Ysewyn * @author Tim Ysewyn
*/ */
public class CloudFoundryNativeReactiveDiscoveryClient public class CloudFoundryNativeReactiveDiscoveryClient implements ReactiveDiscoveryClient {
implements ReactiveDiscoveryClient {
private final CloudFoundryService cloudFoundryService; private final CloudFoundryService cloudFoundryService;
@@ -46,8 +45,8 @@ public class CloudFoundryNativeReactiveDiscoveryClient
private final CloudFoundryDiscoveryProperties properties; private final CloudFoundryDiscoveryProperties properties;
CloudFoundryNativeReactiveDiscoveryClient(CloudFoundryOperations operations, CloudFoundryNativeReactiveDiscoveryClient(CloudFoundryOperations operations, CloudFoundryService svc,
CloudFoundryService svc, CloudFoundryDiscoveryProperties properties) { CloudFoundryDiscoveryProperties properties) {
this.cloudFoundryService = svc; this.cloudFoundryService = svc;
this.cloudFoundryOperations = operations; this.cloudFoundryOperations = operations;
this.properties = properties; this.properties = properties;
@@ -66,8 +65,7 @@ public class CloudFoundryNativeReactiveDiscoveryClient
@Override @Override
public Flux<String> getServices() { public Flux<String> getServices() {
return this.cloudFoundryOperations.applications().list() return this.cloudFoundryOperations.applications().list().map(ApplicationSummary::getName);
.map(ApplicationSummary::getName);
} }
@Override @Override
@@ -75,8 +73,7 @@ public class CloudFoundryNativeReactiveDiscoveryClient
return this.properties.getOrder(); return this.properties.getOrder();
} }
protected ServiceInstance mapApplicationInstanceToServiceInstance( protected ServiceInstance mapApplicationInstanceToServiceInstance(Tuple2<ApplicationDetail, InstanceDetail> tuple) {
Tuple2<ApplicationDetail, InstanceDetail> tuple) {
ApplicationDetail applicationDetail = tuple.getT1(); ApplicationDetail applicationDetail = tuple.getT1();
InstanceDetail instanceDetail = tuple.getT2(); InstanceDetail instanceDetail = tuple.getT2();
@@ -84,16 +81,14 @@ public class CloudFoundryNativeReactiveDiscoveryClient
String applicationIndex = instanceDetail.getIndex(); String applicationIndex = instanceDetail.getIndex();
String instanceId = applicationId + "." + applicationIndex; String instanceId = applicationId + "." + applicationIndex;
String name = applicationDetail.getName(); String name = applicationDetail.getName();
String url = applicationDetail.getUrls().size() > 0 String url = applicationDetail.getUrls().size() > 0 ? applicationDetail.getUrls().get(0) : null;
? applicationDetail.getUrls().get(0) : null;
boolean secure = (url + "").toLowerCase().startsWith("https"); boolean secure = (url + "").toLowerCase().startsWith("https");
HashMap<String, String> metadata = new HashMap<>(); HashMap<String, String> metadata = new HashMap<>();
metadata.put("applicationId", applicationId); metadata.put("applicationId", applicationId);
metadata.put("instanceId", applicationIndex); metadata.put("instanceId", applicationIndex);
return new DefaultServiceInstance(instanceId, name, url, secure ? 443 : 80, return new DefaultServiceInstance(instanceId, name, url, secure ? 443 : 80, secure, metadata);
secure, metadata);
} }
} }

View File

@@ -55,26 +55,22 @@ import org.springframework.context.annotation.Configuration;
public class CloudFoundryReactiveDiscoveryClientConfiguration { public class CloudFoundryReactiveDiscoveryClientConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", havingValue = "false",
havingValue = "false", matchIfMissing = true) matchIfMissing = true)
public static class CloudFoundryNativeReactiveDiscoveryClientConfig { public static class CloudFoundryNativeReactiveDiscoveryClientConfig {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public CloudFoundryNativeReactiveDiscoveryClient nativeCloudFoundryDiscoveryClient( public CloudFoundryNativeReactiveDiscoveryClient nativeCloudFoundryDiscoveryClient(CloudFoundryOperations cf,
CloudFoundryOperations cf, CloudFoundryService svc, CloudFoundryService svc, CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) {
CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) { return new CloudFoundryNativeReactiveDiscoveryClient(cf, svc, cloudFoundryDiscoveryProperties);
return new CloudFoundryNativeReactiveDiscoveryClient(cf, svc,
cloudFoundryDiscoveryProperties);
} }
@Bean @Bean
@ConditionalOnClass( @ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
@ConditionalOnDiscoveryHealthIndicatorEnabled @ConditionalOnDiscoveryHealthIndicatorEnabled
public ReactiveDiscoveryClientHealthIndicator cloudFoundryReactiveDiscoveryClientHealthIndicator( public ReactiveDiscoveryClientHealthIndicator cloudFoundryReactiveDiscoveryClientHealthIndicator(
CloudFoundryNativeReactiveDiscoveryClient client, CloudFoundryNativeReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties) {
DiscoveryClientHealthIndicatorProperties properties) {
return new ReactiveDiscoveryClientHealthIndicator(client, properties); return new ReactiveDiscoveryClientHealthIndicator(client, properties);
} }
@@ -87,34 +83,27 @@ public class CloudFoundryReactiveDiscoveryClientConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-dns", havingValue = "true")
havingValue = "true")
public static class DnsConfig { public static class DnsConfig {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty( @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-container-ip", havingValue = "true")
value = "spring.cloud.cloudfoundry.discovery.use-container-ip",
havingValue = "true")
public static class SimpleDnsConfig { public static class SimpleDnsConfig {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public SimpleDnsBasedReactiveDiscoveryClient dnsBasedReactiveDiscoveryClient( public SimpleDnsBasedReactiveDiscoveryClient dnsBasedReactiveDiscoveryClient(
ObjectProvider<ServiceIdToHostnameConverter> provider, ObjectProvider<ServiceIdToHostnameConverter> provider, CloudFoundryDiscoveryProperties properties) {
CloudFoundryDiscoveryProperties properties) {
ServiceIdToHostnameConverter converter = provider.getIfAvailable(); ServiceIdToHostnameConverter converter = provider.getIfAvailable();
return converter == null return converter == null ? new SimpleDnsBasedReactiveDiscoveryClient(properties)
? new SimpleDnsBasedReactiveDiscoveryClient(properties)
: new SimpleDnsBasedReactiveDiscoveryClient(converter); : new SimpleDnsBasedReactiveDiscoveryClient(converter);
} }
@Bean @Bean
@ConditionalOnClass( @ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
@ConditionalOnDiscoveryHealthIndicatorEnabled @ConditionalOnDiscoveryHealthIndicatorEnabled
public ReactiveDiscoveryClientHealthIndicator cloudFoundryReactiveDiscoveryClientHealthIndicator( public ReactiveDiscoveryClientHealthIndicator cloudFoundryReactiveDiscoveryClientHealthIndicator(
SimpleDnsBasedReactiveDiscoveryClient client, SimpleDnsBasedReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties) {
DiscoveryClientHealthIndicatorProperties properties) {
return new ReactiveDiscoveryClientHealthIndicator(client, properties); return new ReactiveDiscoveryClientHealthIndicator(client, properties);
} }
@@ -127,23 +116,19 @@ public class CloudFoundryReactiveDiscoveryClientConfiguration {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnProperty( @ConditionalOnProperty(value = "spring.cloud.cloudfoundry.discovery.use-container-ip", havingValue = "false",
value = "spring.cloud.cloudfoundry.discovery.use-container-ip", matchIfMissing = true)
havingValue = "false", matchIfMissing = true)
public static class AppServiceConfig { public static class AppServiceConfig {
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public CloudFoundryAppServiceReactiveDiscoveryClient appServiceReactiveDiscoveryClient( public CloudFoundryAppServiceReactiveDiscoveryClient appServiceReactiveDiscoveryClient(
CloudFoundryOperations cf, CloudFoundryService svc, CloudFoundryOperations cf, CloudFoundryService svc, CloudFoundryDiscoveryProperties properties) {
CloudFoundryDiscoveryProperties properties) { return new CloudFoundryAppServiceReactiveDiscoveryClient(cf, svc, properties);
return new CloudFoundryAppServiceReactiveDiscoveryClient(cf, svc,
properties);
} }
@Bean @Bean
@ConditionalOnClass( @ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
@ConditionalOnDiscoveryHealthIndicatorEnabled @ConditionalOnDiscoveryHealthIndicatorEnabled
public ReactiveDiscoveryClientHealthIndicator cloudFoundryReactiveDiscoveryClientHealthIndicator( public ReactiveDiscoveryClientHealthIndicator cloudFoundryReactiveDiscoveryClientHealthIndicator(
CloudFoundryAppServiceReactiveDiscoveryClient client, CloudFoundryAppServiceReactiveDiscoveryClient client,

View File

@@ -30,8 +30,7 @@ import org.springframework.stereotype.Component;
* @author Tim Ysewyn * @author Tim Ysewyn
*/ */
@Component @Component
public class CloudFoundryReactiveHeartbeatSender public class CloudFoundryReactiveHeartbeatSender implements ApplicationEventPublisherAware {
implements ApplicationEventPublisherAware {
private final ReactiveDiscoveryClient client; private final ReactiveDiscoveryClient client;
@@ -41,12 +40,10 @@ public class CloudFoundryReactiveHeartbeatSender
this.client = client; this.client = client;
} }
@Scheduled( @Scheduled(fixedDelayString = "${spring.cloud.cloudfoundry.discovery.heartbeatFrequency:5000}")
fixedDelayString = "${spring.cloud.cloudfoundry.discovery.heartbeatFrequency:5000}")
public void poll() { public void poll() {
if (this.publisher != null) { if (this.publisher != null) {
this.publisher.publishEvent( this.publisher.publishEvent(new HeartbeatEvent(this.client, this.client.getServices()));
new HeartbeatEvent(this.client, this.client.getServices()));
} }
} }

View File

@@ -42,18 +42,15 @@ import org.springframework.cloud.cloudfoundry.discovery.CloudFoundryDiscoveryPro
*/ */
public class SimpleDnsBasedReactiveDiscoveryClient implements ReactiveDiscoveryClient { public class SimpleDnsBasedReactiveDiscoveryClient implements ReactiveDiscoveryClient {
private static final Logger log = LoggerFactory private static final Logger log = LoggerFactory.getLogger(SimpleDnsBasedReactiveDiscoveryClient.class);
.getLogger(SimpleDnsBasedReactiveDiscoveryClient.class);
private final ServiceIdToHostnameConverter serviceIdToHostnameConverter; private final ServiceIdToHostnameConverter serviceIdToHostnameConverter;
public SimpleDnsBasedReactiveDiscoveryClient( public SimpleDnsBasedReactiveDiscoveryClient(ServiceIdToHostnameConverter serviceIdToHostnameConverter) {
ServiceIdToHostnameConverter serviceIdToHostnameConverter) {
this.serviceIdToHostnameConverter = serviceIdToHostnameConverter; this.serviceIdToHostnameConverter = serviceIdToHostnameConverter;
} }
public SimpleDnsBasedReactiveDiscoveryClient( public SimpleDnsBasedReactiveDiscoveryClient(CloudFoundryDiscoveryProperties properties) {
CloudFoundryDiscoveryProperties properties) {
this(serviceId -> serviceId + "." + properties.getInternalDomain()); this(serviceId -> serviceId + "." + properties.getInternalDomain());
} }
@@ -64,10 +61,8 @@ public class SimpleDnsBasedReactiveDiscoveryClient implements ReactiveDiscoveryC
@Override @Override
public Flux<ServiceInstance> getInstances(String serviceId) { public Flux<ServiceInstance> getInstances(String serviceId) {
return Mono.justOrEmpty(serviceIdToHostnameConverter.toHostname(serviceId)) return Mono.justOrEmpty(serviceIdToHostnameConverter.toHostname(serviceId)).flatMapMany(getInetAddresses())
.flatMapMany(getInetAddresses()) .map(address -> new DefaultServiceInstance(serviceId, address.getHostAddress(), 8080, false));
.map(address -> new DefaultServiceInstance(serviceId,
address.getHostAddress(), 8080, false));
} }
private Function<String, Publisher<? extends InetAddress>> getInetAddresses() { private Function<String, Publisher<? extends InetAddress>> getInetAddresses() {

View File

@@ -50,26 +50,23 @@ public class CloudFoundryAppServiceDiscoveryClientTest {
public void setUp() { public void setUp() {
this.cloudFoundryOperations = mock(CloudFoundryOperations.class); this.cloudFoundryOperations = mock(CloudFoundryOperations.class);
this.cloudFoundryService = mock(CloudFoundryService.class); this.cloudFoundryService = mock(CloudFoundryService.class);
this.discoveryClient = new CloudFoundryAppServiceDiscoveryClient( this.discoveryClient = new CloudFoundryAppServiceDiscoveryClient(this.cloudFoundryOperations,
this.cloudFoundryOperations, this.cloudFoundryService, this.cloudFoundryService, new CloudFoundryDiscoveryProperties());
new CloudFoundryDiscoveryProperties());
} }
@Test @Test
public void getInstancesOneInstance() { public void getInstancesOneInstance() {
String serviceId = "billing"; String serviceId = "billing";
ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing1") ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing1").name("billing").instances(1)
.name("billing").instances(1).memoryLimit(1024).stack("cflinux2") .memoryLimit(1024).stack("cflinux2").diskQuota(1024).requestedState("Running").runningInstances(1)
.diskQuota(1024).requestedState("Running").runningInstances(1)
.urls("billing.apps.example.com", "billing.apps.internal").build(); .urls("billing.apps.example.com", "billing.apps.internal").build();
given(this.cloudFoundryService.getApplicationInstances(serviceId)) given(this.cloudFoundryService.getApplicationInstances(serviceId))
.willReturn(Flux.just(Tuples.of(applicationDetail, .willReturn(Flux.just(Tuples.of(applicationDetail, InstanceDetail.builder().index("0").build())));
InstanceDetail.builder().index("0").build())));
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
assertThat(instances).hasSize(1); assertThat(instances).hasSize(1);
assertThat(instances.get(0)).isEqualTo(new DefaultServiceInstance(serviceId, assertThat(instances.get(0)).isEqualTo(new DefaultServiceInstance(serviceId, "0.billing.apps.internal", 8080,
"0.billing.apps.internal", 8080, false, new HashMap<String, String>() { false, new HashMap<String, String>() {
{ {
put("applicationId", "billing1"); put("applicationId", "billing1");
put("instanceId", "0"); put("instanceId", "0");
@@ -80,37 +77,32 @@ public class CloudFoundryAppServiceDiscoveryClientTest {
@Test @Test
public void getInstancesThreeInstance() { public void getInstancesThreeInstance() {
String serviceId = "billing"; String serviceId = "billing";
ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing-id") ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing-id").name("billing").instances(3)
.name("billing").instances(3).memoryLimit(1024).stack("cflinux2") .memoryLimit(1024).stack("cflinux2").diskQuota(1024).requestedState("Running").runningInstances(3)
.diskQuota(1024).requestedState("Running").runningInstances(3)
.urls("billing.apps.example.com", "billing.apps.internal").build(); .urls("billing.apps.example.com", "billing.apps.internal").build();
given(this.cloudFoundryService.getApplicationInstances(serviceId)) given(this.cloudFoundryService.getApplicationInstances(serviceId))
.willReturn(Flux.just( .willReturn(Flux.just(Tuples.of(applicationDetail, InstanceDetail.builder().index("0").build()),
Tuples.of(applicationDetail, Tuples.of(applicationDetail, InstanceDetail.builder().index("1").build()),
InstanceDetail.builder().index("0").build()), Tuples.of(applicationDetail, InstanceDetail.builder().index("2").build())));
Tuples.of(applicationDetail,
InstanceDetail.builder().index("1").build()),
Tuples.of(applicationDetail,
InstanceDetail.builder().index("2").build())));
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
assertThat(instances).hasSize(3); assertThat(instances).hasSize(3);
assertThat(instances.get(0)).isEqualTo(new DefaultServiceInstance(serviceId, assertThat(instances.get(0)).isEqualTo(new DefaultServiceInstance(serviceId, "0.billing.apps.internal", 8080,
"0.billing.apps.internal", 8080, false, new HashMap<String, String>() { false, new HashMap<String, String>() {
{ {
put("applicationId", "billing-id"); put("applicationId", "billing-id");
put("instanceId", "0"); put("instanceId", "0");
} }
})); }));
assertThat(instances.get(1)).isEqualTo(new DefaultServiceInstance(serviceId, assertThat(instances.get(1)).isEqualTo(new DefaultServiceInstance(serviceId, "1.billing.apps.internal", 8080,
"1.billing.apps.internal", 8080, false, new HashMap<String, String>() { false, new HashMap<String, String>() {
{ {
put("applicationId", "billing-id"); put("applicationId", "billing-id");
put("instanceId", "1"); put("instanceId", "1");
} }
})); }));
assertThat(instances.get(2)).isEqualTo(new DefaultServiceInstance(serviceId, assertThat(instances.get(2)).isEqualTo(new DefaultServiceInstance(serviceId, "2.billing.apps.internal", 8080,
"2.billing.apps.internal", 8080, false, new HashMap<String, String>() { false, new HashMap<String, String>() {
{ {
put("applicationId", "billing-id"); put("applicationId", "billing-id");
put("instanceId", "2"); put("instanceId", "2");
@@ -121,13 +113,11 @@ public class CloudFoundryAppServiceDiscoveryClientTest {
@Test @Test
public void getInstancesEmpty() { public void getInstancesEmpty() {
String serviceId = "billing"; String serviceId = "billing";
ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing1") ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing1").name("billing").instances(1)
.name("billing").instances(1).memoryLimit(1024).stack("cflinux2") .memoryLimit(1024).stack("cflinux2").diskQuota(1024).requestedState("Running").runningInstances(1)
.diskQuota(1024).requestedState("Running").runningInstances(1)
.url("billing.apps.example.com").build(); .url("billing.apps.example.com").build();
given(this.cloudFoundryService.getApplicationInstances(serviceId)) given(this.cloudFoundryService.getApplicationInstances(serviceId))
.willReturn(Flux.just(Tuples.of(applicationDetail, .willReturn(Flux.just(Tuples.of(applicationDetail, InstanceDetail.builder().index("0").build())));
InstanceDetail.builder().index("0").build())));
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
assertThat(instances).isEmpty(); assertThat(instances).isEmpty();

View File

@@ -37,41 +37,31 @@ import static org.assertj.core.api.Assertions.assertThat;
public class CloudFoundryDiscoveryClientConfigurationTest { public class CloudFoundryDiscoveryClientConfigurationTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations .withConfiguration(AutoConfigurations.of(CloudFoundryDiscoveryClientConfiguration.class));
.of(CloudFoundryDiscoveryClientConfiguration.class));
@Test @Test
public void testDefault() { public void testDefault() {
this.contextRunner.withUserConfiguration(CloudFoundryConfig.class) this.contextRunner.withUserConfiguration(CloudFoundryConfig.class).run((context) -> {
.run((context) -> { DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
DiscoveryClient discoveryClient = context assertThat(discoveryClient.getClass()).isEqualTo(CloudFoundryDiscoveryClient.class);
.getBean(DiscoveryClient.class); });
assertThat(discoveryClient.getClass())
.isEqualTo(CloudFoundryDiscoveryClient.class);
});
} }
@Test @Test
public void testUseDnsTrue() { public void testUseDnsTrue() {
this.contextRunner.withUserConfiguration(CloudFoundryConfig.class) this.contextRunner.withUserConfiguration(CloudFoundryConfig.class)
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true") .withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true").run((context) -> {
.run((context) -> { DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
DiscoveryClient discoveryClient = context assertThat(discoveryClient.getClass()).isEqualTo(CloudFoundryAppServiceDiscoveryClient.class);
.getBean(DiscoveryClient.class);
assertThat(discoveryClient.getClass())
.isEqualTo(CloudFoundryAppServiceDiscoveryClient.class);
}); });
} }
@Test @Test
public void testUseDnsFalse() { public void testUseDnsFalse() {
this.contextRunner.withUserConfiguration(CloudFoundryConfig.class) this.contextRunner.withUserConfiguration(CloudFoundryConfig.class)
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=false") .withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=false").run((context) -> {
.run((context) -> { DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
DiscoveryClient discoveryClient = context assertThat(discoveryClient.getClass()).isEqualTo(CloudFoundryDiscoveryClient.class);
.getBean(DiscoveryClient.class);
assertThat(discoveryClient.getClass())
.isEqualTo(CloudFoundryDiscoveryClient.class);
}); });
} }
@@ -81,23 +71,17 @@ public class CloudFoundryDiscoveryClientConfigurationTest {
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true", .withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true",
"spring.cloud.cloudfoundry.discovery.use-container-ip=false") "spring.cloud.cloudfoundry.discovery.use-container-ip=false")
.run((context) -> { .run((context) -> {
DiscoveryClient discoveryClient = context DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
.getBean(DiscoveryClient.class); assertThat(discoveryClient.getClass()).isEqualTo(CloudFoundryAppServiceDiscoveryClient.class);
assertThat(discoveryClient.getClass())
.isEqualTo(CloudFoundryAppServiceDiscoveryClient.class);
}); });
} }
@Test @Test
public void testUseContainerIpTrue() { public void testUseContainerIpTrue() {
this.contextRunner this.contextRunner.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true",
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true", "spring.cloud.cloudfoundry.discovery.use-container-ip=true").run((context) -> {
"spring.cloud.cloudfoundry.discovery.use-container-ip=true") DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
.run((context) -> { assertThat(discoveryClient.getClass()).isEqualTo(SimpleDnsBasedDiscoveryClient.class);
DiscoveryClient discoveryClient = context
.getBean(DiscoveryClient.class);
assertThat(discoveryClient.getClass())
.isEqualTo(SimpleDnsBasedDiscoveryClient.class);
}); });
} }

View File

@@ -58,42 +58,35 @@ public class CloudFoundryDiscoveryClientTest {
public void setUp() { public void setUp() {
this.ops = mock(CloudFoundryOperations.class); this.ops = mock(CloudFoundryOperations.class);
this.svc = mock(CloudFoundryService.class); this.svc = mock(CloudFoundryService.class);
this.cloudFoundryDiscoveryClient = new CloudFoundryDiscoveryClient(this.ops, this.cloudFoundryDiscoveryClient = new CloudFoundryDiscoveryClient(this.ops, this.svc,
this.svc, new CloudFoundryDiscoveryProperties()); new CloudFoundryDiscoveryProperties());
} }
@Test @Test
public void testServiceResolution() { public void testServiceResolution() {
Applications apps = mock(Applications.class); Applications apps = mock(Applications.class);
ApplicationSummary s = ApplicationSummary.builder() ApplicationSummary s = ApplicationSummary.builder().id(UUID.randomUUID().toString()).instances(2)
.id(UUID.randomUUID().toString()).instances(2).memoryLimit(1024) .memoryLimit(1024).requestedState("requestedState").diskQuota(1024).name(this.hiServiceServiceId)
.requestedState("requestedState").diskQuota(1024) .runningInstances(2).build();
.name(this.hiServiceServiceId).runningInstances(2).build();
Mockito.when(apps.list()).thenReturn(Flux.just(s)); Mockito.when(apps.list()).thenReturn(Flux.just(s));
Mockito.when(this.ops.applications()).thenReturn(apps); Mockito.when(this.ops.applications()).thenReturn(apps);
List<String> serviceNames = this.cloudFoundryDiscoveryClient.getServices(); List<String> serviceNames = this.cloudFoundryDiscoveryClient.getServices();
assertThat(serviceNames.contains(this.hiServiceServiceId)) assertThat(serviceNames.contains(this.hiServiceServiceId)).as("there should be one registered service.")
.as("there should be one registered service.").isTrue(); .isTrue();
serviceNames.forEach(serviceName -> this.log serviceNames.forEach(serviceName -> this.log.debug("\t discovered serviceName: " + serviceName));
.debug("\t discovered serviceName: " + serviceName));
} }
@Test @Test
public void testInstances() { public void testInstances() {
ApplicationDetail applicationDetail = ApplicationDetail.builder().instances(2) ApplicationDetail applicationDetail = ApplicationDetail.builder().instances(2).name("my-app").stack("stack")
.name("my-app").stack("stack").memoryLimit(1024).id("id") .memoryLimit(1024).id("id").requestedState("requestedState").runningInstances(2)
.requestedState("requestedState").runningInstances(2)
.url("http://my-app-cfapps-io").diskQuota(20).build(); .url("http://my-app-cfapps-io").diskQuota(20).build();
InstanceDetail instanceDetail = InstanceDetail.builder().index("0").build(); InstanceDetail instanceDetail = InstanceDetail.builder().index("0").build();
Tuple2<ApplicationDetail, InstanceDetail> tuple2 = Tuples.of(applicationDetail, Tuple2<ApplicationDetail, InstanceDetail> tuple2 = Tuples.of(applicationDetail, instanceDetail);
instanceDetail); Mockito.when(this.svc.getApplicationInstances(this.hiServiceServiceId)).thenReturn(Flux.just(tuple2));
Mockito.when(this.svc.getApplicationInstances(this.hiServiceServiceId)) List<ServiceInstance> instances = this.cloudFoundryDiscoveryClient.getInstances(this.hiServiceServiceId);
.thenReturn(Flux.just(tuple2));
List<ServiceInstance> instances = this.cloudFoundryDiscoveryClient
.getInstances(this.hiServiceServiceId);
assertThat(instances.size()).as("Wrong instances: " + instances).isEqualTo(1); assertThat(instances.size()).as("Wrong instances: " + instances).isEqualTo(1);
assertThat(instances.get(0).getInstanceId()).as("Wrong instance ID") assertThat(instances.get(0).getInstanceId()).as("Wrong instance ID").isEqualTo("id.0");
.isEqualTo("id.0");
} }
} }

View File

@@ -49,22 +49,17 @@ class CloudFoundryAppServiceReactiveDiscoveryClientTests {
@Test @Test
public void shouldReturnFluxOfServiceInstances() { public void shouldReturnFluxOfServiceInstances() {
ApplicationDetail appDetail1 = ApplicationDetail.builder() ApplicationDetail appDetail1 = ApplicationDetail.builder().id(UUID.randomUUID().toString()).stack("stack")
.id(UUID.randomUUID().toString()).stack("stack").instances(1) .instances(1).memoryLimit(1024).requestedState("requestedState").diskQuota(1024).name("service")
.memoryLimit(1024).requestedState("requestedState").diskQuota(1024) .runningInstances(1).url("instance.apps.internal").build();
.name("service").runningInstances(1).url("instance.apps.internal")
.build();
Tuple2<ApplicationDetail, InstanceDetail> instance1 = Tuples.of(appDetail1, Tuple2<ApplicationDetail, InstanceDetail> instance1 = Tuples.of(appDetail1,
InstanceDetail.builder().index("0").build()); InstanceDetail.builder().index("0").build());
ApplicationDetail appDetail2 = ApplicationDetail.builder() ApplicationDetail appDetail2 = ApplicationDetail.builder().id(UUID.randomUUID().toString()).stack("stack")
.id(UUID.randomUUID().toString()).stack("stack").instances(1) .instances(1).memoryLimit(1024).requestedState("requestedState").diskQuota(1024).name("service")
.memoryLimit(1024).requestedState("requestedState").diskQuota(1024) .runningInstances(1).url("instance.apps.not.internal").build();
.name("service").runningInstances(1).url("instance.apps.not.internal")
.build();
Tuple2<ApplicationDetail, InstanceDetail> instance2 = Tuples.of(appDetail2, Tuple2<ApplicationDetail, InstanceDetail> instance2 = Tuples.of(appDetail2,
InstanceDetail.builder().index("0").build()); InstanceDetail.builder().index("0").build());
when(this.svc.getApplicationInstances("service")) when(this.svc.getApplicationInstances("service")).thenReturn(Flux.just(instance1, instance2));
.thenReturn(Flux.just(instance1, instance2));
Flux<ServiceInstance> instances = this.client.getInstances("service"); Flux<ServiceInstance> instances = this.client.getInstances("service");
StepVerifier.create(instances).expectNextCount(1).expectComplete().verify(); StepVerifier.create(instances).expectNextCount(1).expectComplete().verify();
} }

View File

@@ -62,8 +62,7 @@ class CloudFoundryNativeReactiveDiscoveryClientTests {
@Test @Test
public void verifyDefaults() { public void verifyDefaults() {
when(properties.getOrder()).thenReturn(0); when(properties.getOrder()).thenReturn(0);
assertThat(client.description()) assertThat(client.description()).isEqualTo("CF Reactive Service Discovery Client");
.isEqualTo("CF Reactive Service Discovery Client");
assertThat(client.getOrder()).isEqualTo(0); assertThat(client.getOrder()).isEqualTo(0);
} }
@@ -71,10 +70,9 @@ class CloudFoundryNativeReactiveDiscoveryClientTests {
public void shouldReturnFluxOfServices() { public void shouldReturnFluxOfServices() {
Applications apps = mock(Applications.class); Applications apps = mock(Applications.class);
when(operations.applications()).thenReturn(apps); when(operations.applications()).thenReturn(apps);
ApplicationSummary summary = ApplicationSummary.builder() ApplicationSummary summary = ApplicationSummary.builder().id(UUID.randomUUID().toString()).instances(1)
.id(UUID.randomUUID().toString()).instances(1).memoryLimit(1024) .memoryLimit(1024).requestedState("requestedState").diskQuota(1024).name("service").runningInstances(1)
.requestedState("requestedState").diskQuota(1024).name("service") .build();
.runningInstances(1).build();
when(apps.list()).thenReturn(Flux.just(summary)); when(apps.list()).thenReturn(Flux.just(summary));
Flux<String> services = this.client.getServices(); Flux<String> services = this.client.getServices();
StepVerifier.create(services).expectNext("service").expectComplete().verify(); StepVerifier.create(services).expectNext("service").expectComplete().verify();
@@ -89,13 +87,11 @@ class CloudFoundryNativeReactiveDiscoveryClientTests {
@Test @Test
public void shouldReturnFluxOfServiceInstances() { public void shouldReturnFluxOfServiceInstances() {
ApplicationDetail applicationDetail = ApplicationDetail.builder() ApplicationDetail applicationDetail = ApplicationDetail.builder().id(UUID.randomUUID().toString())
.id(UUID.randomUUID().toString()).stack("stack").instances(1) .stack("stack").instances(1).memoryLimit(1024).requestedState("requestedState").diskQuota(1024)
.memoryLimit(1024).requestedState("requestedState").diskQuota(1024)
.name("service").runningInstances(1).build(); .name("service").runningInstances(1).build();
InstanceDetail instanceDetail = InstanceDetail.builder().index("0").build(); InstanceDetail instanceDetail = InstanceDetail.builder().index("0").build();
Tuple2<ApplicationDetail, InstanceDetail> instance = Tuples.of(applicationDetail, Tuple2<ApplicationDetail, InstanceDetail> instance = Tuples.of(applicationDetail, instanceDetail);
instanceDetail);
when(this.svc.getApplicationInstances("service")).thenReturn(Flux.just(instance)); when(this.svc.getApplicationInstances("service")).thenReturn(Flux.just(instance));
Flux<ServiceInstance> instances = this.client.getInstances("service"); Flux<ServiceInstance> instances = this.client.getInstances("service");
StepVerifier.create(instances).expectNextCount(1).expectComplete().verify(); StepVerifier.create(instances).expectNextCount(1).expectComplete().verify();

View File

@@ -39,138 +39,100 @@ import static org.mockito.Mockito.mock;
*/ */
class CloudFoundryReactiveDiscoveryClientConfigurationTests { class CloudFoundryReactiveDiscoveryClientConfigurationTests {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner() private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(AutoConfigurations
.withConfiguration( .of(MockedCloudFoundryConfiguration.class, CloudFoundryReactiveDiscoveryClientConfiguration.class));
AutoConfigurations.of(MockedCloudFoundryConfiguration.class,
CloudFoundryReactiveDiscoveryClientConfiguration.class));
@Test @Test
public void shouldNotHaveDiscoveryClientsWhenDiscoveryDisabled() { public void shouldNotHaveDiscoveryClientsWhenDiscoveryDisabled() {
contextRunner.withPropertyValues("spring.cloud.discovery.enabled=false") contextRunner.withPropertyValues("spring.cloud.discovery.enabled=false").run(context -> {
.run(context -> { assertThat(context).doesNotHaveBean("cloudFoundryHeartbeatSender");
assertThat(context).doesNotHaveBean("cloudFoundryHeartbeatSender"); assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class); assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).doesNotHaveBean( });
ReactiveDiscoveryClientHealthIndicator.class);
});
} }
@Test @Test
public void shouldNotHaveDiscoveryClientsWhenReactiveDiscoveryDisabled() { public void shouldNotHaveDiscoveryClientsWhenReactiveDiscoveryDisabled() {
contextRunner.withPropertyValues("spring.cloud.discovery.reactive.enabled=false") contextRunner.withPropertyValues("spring.cloud.discovery.reactive.enabled=false").run(context -> {
.run(context -> { assertThat(context).doesNotHaveBean("cloudFoundryHeartbeatSender");
assertThat(context).doesNotHaveBean("cloudFoundryHeartbeatSender"); assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class); assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).doesNotHaveBean( });
ReactiveDiscoveryClientHealthIndicator.class);
});
} }
@Test @Test
public void shouldNotHaveDiscoveryClientsWhenCloudFoundryDiscoveryDisabled() { public void shouldNotHaveDiscoveryClientsWhenCloudFoundryDiscoveryDisabled() {
contextRunner contextRunner.withPropertyValues("spring.cloud.cloudfoundry.discovery.enabled=false").run(context -> {
.withPropertyValues("spring.cloud.cloudfoundry.discovery.enabled=false") assertThat(context).doesNotHaveBean("cloudFoundryHeartbeatSender");
.run(context -> { assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean("cloudFoundryHeartbeatSender"); assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class); });
assertThat(context).doesNotHaveBean(
ReactiveDiscoveryClientHealthIndicator.class);
});
} }
@Test @Test
public void shouldUseNativeDiscovery() { public void shouldUseNativeDiscovery() {
contextRunner contextRunner.withConfiguration(AutoConfigurations.of(ReactiveCommonsClientAutoConfiguration.class))
.withConfiguration(AutoConfigurations
.of(ReactiveCommonsClientAutoConfiguration.class))
.run(context -> { .run(context -> {
assertThat(context) assertThat(context).hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
.hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class); assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class);
assertThat(context).hasBean("nativeCloudFoundryDiscoveryClient"); assertThat(context).hasBean("nativeCloudFoundryDiscoveryClient");
assertThat(context) assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
.hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
}); });
} }
@Test @Test
public void shouldUseDnsDiscovery() { public void shouldUseDnsDiscovery() {
contextRunner contextRunner.withConfiguration(AutoConfigurations.of(ReactiveCommonsClientAutoConfiguration.class))
.withConfiguration(AutoConfigurations
.of(ReactiveCommonsClientAutoConfiguration.class))
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true", .withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true",
"spring.cloud.cloudfoundry.discovery.use-container-ip=true") "spring.cloud.cloudfoundry.discovery.use-container-ip=true")
.run(context -> { .run(context -> {
assertThat(context) assertThat(context).hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
.hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class); assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class);
assertThat(context).hasBean("dnsBasedReactiveDiscoveryClient"); assertThat(context).hasBean("dnsBasedReactiveDiscoveryClient");
assertThat(context) assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
.hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
}); });
} }
@Test @Test
public void shouldUseAppServiceDiscovery() { public void shouldUseAppServiceDiscovery() {
contextRunner contextRunner.withConfiguration(AutoConfigurations.of(ReactiveCommonsClientAutoConfiguration.class))
.withConfiguration(AutoConfigurations
.of(ReactiveCommonsClientAutoConfiguration.class))
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true", .withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true",
"spring.cloud.cloudfoundry.discovery.use-container-ip=false") "spring.cloud.cloudfoundry.discovery.use-container-ip=false")
.run(context -> { .run(context -> {
assertThat(context) assertThat(context).hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
.hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class); assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class);
assertThat(context).hasBean("appServiceReactiveDiscoveryClient"); assertThat(context).hasBean("appServiceReactiveDiscoveryClient");
assertThat(context) assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
.hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
}); });
} }
@Test @Test
public void shouldUseCustomServiceDiscovery() { public void shouldUseCustomServiceDiscovery() {
contextRunner contextRunner.withConfiguration(AutoConfigurations.of(ReactiveCommonsClientAutoConfiguration.class))
.withConfiguration(AutoConfigurations .withUserConfiguration(CustomCloudFoundryReactiveDiscoveryClientConfiguration.class).run(context -> {
.of(ReactiveCommonsClientAutoConfiguration.class)) assertThat(context).hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
.withUserConfiguration( assertThat(context).getBeans(ReactiveDiscoveryClient.class).hasSize(2);
CustomCloudFoundryReactiveDiscoveryClientConfiguration.class)
.run(context -> {
assertThat(context)
.hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
assertThat(context).getBeans(ReactiveDiscoveryClient.class)
.hasSize(2);
assertThat(context).hasBean("nativeCloudFoundryDiscoveryClient"); assertThat(context).hasBean("nativeCloudFoundryDiscoveryClient");
assertThat(context) assertThat(context).hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
.hasSingleBean(ReactiveDiscoveryClientHealthIndicator.class);
}); });
} }
@Test @Test
public void worksWithoutWebflux() { public void worksWithoutWebflux() {
contextRunner contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.web.reactive")).run(context -> {
.withClassLoader( assertThat(context).doesNotHaveBean(CloudFoundryReactiveHeartbeatSender.class);
new FilteredClassLoader("org.springframework.web.reactive")) assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class);
.run(context -> { assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context) });
.doesNotHaveBean(CloudFoundryReactiveHeartbeatSender.class);
assertThat(context).doesNotHaveBean(ReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(
ReactiveDiscoveryClientHealthIndicator.class);
});
} }
@Test @Test
public void worksWithoutActuator() { public void worksWithoutActuator() {
contextRunner contextRunner.withClassLoader(new FilteredClassLoader("org.springframework.boot.actuate")).run(context -> {
.withClassLoader( assertThat(context).hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
new FilteredClassLoader("org.springframework.boot.actuate")) assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class);
.run(context -> { assertThat(context).doesNotHaveBean(ReactiveDiscoveryClientHealthIndicator.class);
assertThat(context) });
.hasSingleBean(CloudFoundryReactiveHeartbeatSender.class);
assertThat(context).hasSingleBean(ReactiveDiscoveryClient.class);
assertThat(context).doesNotHaveBean(
ReactiveDiscoveryClientHealthIndicator.class);
});
} }
@TestConfiguration @TestConfiguration

View File

@@ -59,8 +59,7 @@ public class CloudFoundryApplication {
Log log = LogFactory.getLog(getClass()); Log log = LogFactory.getLog(getClass());
return args -> discoveryClient.getServices().forEach(svc -> { return args -> discoveryClient.getServices().forEach(svc -> {
log.info("service = " + svc); log.info("service = " + svc);
discoveryClient.getInstances(svc) discoveryClient.getInstances(svc).forEach(si -> log.info("\tinstance = " + si));
.forEach(si -> log.info("\tinstance = " + si));
}); });
} }

View File

@@ -35,11 +35,9 @@ import org.springframework.util.StringUtils;
* @author Dave Syer * @author Dave Syer
* *
*/ */
public class VcapServiceCredentialsEnvironmentPostProcessor public class VcapServiceCredentialsEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
implements EnvironmentPostProcessor, Ordered {
static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable static final Bindable<Map<String, Object>> STRING_OBJECT_MAP = Bindable.mapOf(String.class, Object.class);
.mapOf(String.class, Object.class);
// After VcapEnvironmentPostProcessor and ConfigFileEnvironmentPostProcessor so // After VcapEnvironmentPostProcessor and ConfigFileEnvironmentPostProcessor so
// values here can // values here can
@@ -52,63 +50,52 @@ public class VcapServiceCredentialsEnvironmentPostProcessor
} }
@Override @Override
public void postProcessEnvironment(ConfigurableEnvironment environment, public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
SpringApplication application) { Binder.get(environment).bind("vcap.services", STRING_OBJECT_MAP).orElseGet(Collections::emptyMap);
Binder.get(environment).bind("vcap.services", STRING_OBJECT_MAP)
.orElseGet(Collections::emptyMap);
if (!hasChildProperties(environment, "vcap.services")) { if (!hasChildProperties(environment, "vcap.services")) {
return; return;
} }
Map<String, Object> source = new HashMap<>(); Map<String, Object> source = new HashMap<>();
String serviceId; String serviceId;
if (hasChildProperties(environment, "security.oauth2.resource")) { if (hasChildProperties(environment, "security.oauth2.resource")) {
serviceId = environment.getProperty("security.oauth2.resource.service-id", serviceId = environment.getProperty("security.oauth2.resource.service-id", "resource");
"resource");
} }
else { else {
serviceId = environment.getProperty("security.oauth2.sso.service-id", "sso"); serviceId = environment.getProperty("security.oauth2.sso.service-id", "sso");
} }
String authDomain = environment String authDomain = environment.getProperty("vcap.services." + serviceId + ".credentials.auth-domain");
.getProperty("vcap.services." + serviceId + ".credentials.auth-domain");
if (authDomain != null) { if (authDomain != null) {
source.put("security.oauth2.resource.user-info-uri", source.put("security.oauth2.resource.user-info-uri", authDomain + "/userinfo");
authDomain + "/userinfo");
source.put("security.oauth2.resource.jwt.key-uri", authDomain + "/token_key"); source.put("security.oauth2.resource.jwt.key-uri", authDomain + "/token_key");
source.put("security.oauth2.client.access-token-uri", source.put("security.oauth2.client.access-token-uri", authDomain + "/oauth/token");
authDomain + "/oauth/token"); source.put("security.oauth2.client.user-authorization-uri", authDomain + "/oauth/authorize");
source.put("security.oauth2.client.user-authorization-uri",
authDomain + "/oauth/authorize");
} }
else { else {
addProperty(source, environment, serviceId, "resource", "user-info-uri"); addProperty(source, environment, serviceId, "resource", "user-info-uri");
addProperty(source, environment, serviceId, "resource", "token-info-uri"); addProperty(source, environment, serviceId, "resource", "token-info-uri");
addProperty(source, environment, serviceId, "resource.jwt", "key-uri"); addProperty(source, environment, serviceId, "resource.jwt", "key-uri");
addProperty(source, environment, serviceId, "resource", "key-value"); addProperty(source, environment, serviceId, "resource", "key-value");
addProperty(source, environment, serviceId, "client", "access-token-uri", addProperty(source, environment, serviceId, "client", "access-token-uri", "token-uri");
"token-uri"); addProperty(source, environment, serviceId, "client", "user-authorization-uri", "authorization-uri");
addProperty(source, environment, serviceId, "client",
"user-authorization-uri", "authorization-uri");
} }
addProperty(source, environment, serviceId, "client", "client-id"); addProperty(source, environment, serviceId, "client", "client-id");
addProperty(source, environment, serviceId, "client", "client-secret"); addProperty(source, environment, serviceId, "client", "client-secret");
addProperty(source, environment, serviceId, "client", "scope"); addProperty(source, environment, serviceId, "client", "scope");
String resourceId = environment String resourceId = environment.getProperty("vcap.services." + serviceId + ".credentials.id", "");
.getProperty("vcap.services." + serviceId + ".credentials.id", "");
if (StringUtils.hasText(resourceId)) { if (StringUtils.hasText(resourceId)) {
source.put("security.oauth2.resource.id", resourceId); source.put("security.oauth2.resource.id", resourceId);
} }
environment.getPropertySources() environment.getPropertySources().addLast(new MapPropertySource("cloudDefaultSecurityBindings", source));
.addLast(new MapPropertySource("cloudDefaultSecurityBindings", source));
} }
private boolean hasChildProperties(ConfigurableEnvironment environment, String name) { private boolean hasChildProperties(ConfigurableEnvironment environment, String name) {
Map<String, Object> properties = Binder.get(environment) Map<String, Object> properties = Binder.get(environment).bind(name, STRING_OBJECT_MAP)
.bind(name, STRING_OBJECT_MAP).orElseGet(Collections::emptyMap); .orElseGet(Collections::emptyMap);
return !properties.isEmpty(); return !properties.isEmpty();
} }
private void addProperty(Map<String, Object> source, PropertyResolver resolver, private void addProperty(Map<String, Object> source, PropertyResolver resolver, String serviceId, String stem,
String serviceId, String stem, String key, String... altKeys) { String key, String... altKeys) {
String value = resolve(resolver, serviceId, key); String value = resolve(resolver, serviceId, key);
if (StringUtils.hasText(value)) { if (StringUtils.hasText(value)) {
source.put("security.oauth2." + stem + "." + key, value); source.put("security.oauth2." + stem + "." + key, value);
@@ -124,8 +111,7 @@ public class VcapServiceCredentialsEnvironmentPostProcessor
} }
private String resolve(PropertyResolver resolver, String serviceId, String key) { private String resolve(PropertyResolver resolver, String serviceId, String key) {
return resolver.getProperty( return resolver.getProperty(String.format("vcap.services.%s.credentials.%s", serviceId, key), "");
String.format("vcap.services.%s.credentials.%s", serviceId, key), "");
} }
} }

View File

@@ -49,12 +49,10 @@ public class StickyFilterConfiguration {
filter.setOrder(Ordered.LOWEST_PRECEDENCE); filter.setOrder(Ordered.LOWEST_PRECEDENCE);
filter.setFilter(new OncePerRequestFilter() { filter.setFilter(new OncePerRequestFilter() {
@Override @Override
protected void doFilterInternal(HttpServletRequest request, protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
HttpServletResponse response, FilterChain filterChain) FilterChain filterChain) throws ServletException, IOException {
throws ServletException, IOException {
if (!response.containsHeader("Set-Cookie")) { if (!response.containsHeader("Set-Cookie")) {
response.addCookie(new Cookie("JSESSIONID", response.addCookie(new Cookie("JSESSIONID", StickyFilterConfiguration.this.cookie));
StickyFilterConfiguration.this.cookie));
} }
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
} }

View File

@@ -43,85 +43,67 @@ public class VcapServiceCredentialsEnvironmentPostProcessorTests {
@Test @Test
public void noop() { public void noop() {
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
Map<String, Object> properties = Binder.get(this.environment) Map<String, Object> properties = Binder.get(this.environment).bind("security.oauth2", STRING_OBJECT_MAP)
.bind("security.oauth2", STRING_OBJECT_MAP)
.orElseGet(Collections::emptyMap); .orElseGet(Collections::emptyMap);
assertThat(properties.isEmpty()).isTrue(); assertThat(properties.isEmpty()).isTrue();
} }
@Test @Test
public void addClientId() { public void addClientId() {
TestPropertyValues.of("vcap.services.sso.credentials.clientId:foo") TestPropertyValues.of("vcap.services.sso.credentials.clientId:foo").applyTo(this.environment);
.applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.client.client-id}")).isEqualTo("foo");
.resolvePlaceholders("${security.oauth2.client.client-id}"))
.isEqualTo("foo");
} }
@Test @Test
public void addClientIdUnderscores() { public void addClientIdUnderscores() {
TestPropertyValues.of("vcap.services.sso.credentials.client-id:foo") TestPropertyValues.of("vcap.services.sso.credentials.client-id:foo").applyTo(this.environment);
.applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.client.client-id}")).isEqualTo("foo");
.resolvePlaceholders("${security.oauth2.client.client-id}"))
.isEqualTo("foo");
} }
@Test @Test
public void addTokenUri() { public void addTokenUri() {
TestPropertyValues TestPropertyValues.of("vcap.services.sso.credentials.accessTokenUri:http://exampledomain")
.of("vcap.services.sso.credentials.accessTokenUri:http://exampledomain")
.applyTo(this.environment); .applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.client.access-token-uri}"))
.resolvePlaceholders("${security.oauth2.client.access-token-uri}")) .isEqualTo("http://exampledomain");
.isEqualTo("http://exampledomain");
} }
@Test @Test
public void addTokenUriAuthDomain() { public void addTokenUriAuthDomain() {
TestPropertyValues TestPropertyValues.of("vcap.services.sso.credentials.auth-domain:http://exampledomain")
.of("vcap.services.sso.credentials.auth-domain:http://exampledomain")
.applyTo(this.environment); .applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.client.access-token-uri}"))
.resolvePlaceholders("${security.oauth2.client.access-token-uri}")) .isEqualTo("http://exampledomain/oauth/token");
.isEqualTo("http://exampledomain/oauth/token");
} }
@Test @Test
public void addUserInfoUri() { public void addUserInfoUri() {
TestPropertyValues TestPropertyValues.of("vcap.services.sso.credentials.userInfoUri:http://exampledomain")
.of("vcap.services.sso.credentials.userInfoUri:http://exampledomain")
.applyTo(this.environment); .applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.resource.user-info-uri}"))
.resolvePlaceholders("${security.oauth2.resource.user-info-uri}")) .isEqualTo("http://exampledomain");
.isEqualTo("http://exampledomain");
} }
@Test @Test
public void addServiceId() { public void addServiceId() {
TestPropertyValues TestPropertyValues.of("vcap.services.my.credentials.accessTokenUri:http://exampledomain",
.of("vcap.services.my.credentials.accessTokenUri:http://exampledomain", "security.oauth2.sso.serviceId:my").applyTo(this.environment);
"security.oauth2.sso.serviceId:my")
.applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.client.access-token-uri}"))
.resolvePlaceholders("${security.oauth2.client.access-token-uri}")) .isEqualTo("http://exampledomain");
.isEqualTo("http://exampledomain");
} }
@Test @Test
public void addJwtKeyUri() { public void addJwtKeyUri() {
TestPropertyValues.of("vcap.services.sso.credentials.keyUri:http://exampledomain") TestPropertyValues.of("vcap.services.sso.credentials.keyUri:http://exampledomain").applyTo(this.environment);
.applyTo(this.environment);
this.listener.postProcessEnvironment(this.environment, new SpringApplication()); this.listener.postProcessEnvironment(this.environment, new SpringApplication());
assertThat(this.environment assertThat(this.environment.resolvePlaceholders("${security.oauth2.resource.jwt.key-uri}"))
.resolvePlaceholders("${security.oauth2.resource.jwt.key-uri}")) .isEqualTo("http://exampledomain");
.isEqualTo("http://exampledomain");
} }
} }