forked from spring-cloud/spring-cloud-cloudfoundry
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
286 additions
and
0 deletions.
There are no files selected for viewing
70 changes: 70 additions & 0 deletions
70
...g/springframework/cloud/cloudfoundry/discovery/CloudFoundryAppServiceDiscoveryClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
package org.springframework.cloud.cloudfoundry.discovery; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
|
||
import org.cloudfoundry.operations.CloudFoundryOperations; | ||
import org.cloudfoundry.operations.applications.ApplicationDetail; | ||
import org.cloudfoundry.operations.applications.InstanceDetail; | ||
import org.springframework.cloud.client.DefaultServiceInstance; | ||
import org.springframework.cloud.client.ServiceInstance; | ||
import org.springframework.cloud.cloudfoundry.CloudFoundryService; | ||
|
||
/** | ||
* | ||
* Discovery Client implementation using Cloud Foundry's Native DNS based Service | ||
* Discovery | ||
* | ||
* @see <a href="https://github.com/cloudfoundry/cf-app-sd-release">CF App Service | ||
* Discovery Release</a> | ||
* @see <a href= | ||
* "https://www.cloudfoundry.org/blog/polyglot-service-discovery-container-networking-cloud-foundry/">Polyglot | ||
* Service Discovery for Container Networking in Cloud Foundry</a> | ||
* | ||
* @author Toshiaki Maki | ||
*/ | ||
public class CloudFoundryAppServiceDiscoveryClient extends CloudFoundryDiscoveryClient { | ||
|
||
private static final String INTERNAL_DOMAIN = "apps.internal"; | ||
|
||
CloudFoundryAppServiceDiscoveryClient(CloudFoundryOperations cloudFoundryOperations, | ||
CloudFoundryService svc, CloudFoundryDiscoveryProperties cloudFoundryDiscoveryProperties) { | ||
super(cloudFoundryOperations, svc, cloudFoundryDiscoveryProperties); | ||
} | ||
|
||
@Override | ||
public String description() { | ||
return "CF App Service Discovery Client"; | ||
} | ||
|
||
@Override | ||
public List<ServiceInstance> getInstances(String serviceId) { | ||
return getCloudFoundryService() | ||
.getApplicationInstances(serviceId) | ||
.filter(tuple -> tuple.getT1().getUrls().stream() | ||
.anyMatch(this::isInternalDomain)) | ||
.map(tuple -> { | ||
ApplicationDetail applicationDetail = tuple.getT1(); | ||
InstanceDetail instanceDetail = tuple.getT2(); | ||
String applicationId = applicationDetail.getId(); | ||
String applicationIndex = instanceDetail.getIndex(); | ||
String name = applicationDetail.getName(); | ||
String url = applicationDetail.getUrls().stream() | ||
.filter(this::isInternalDomain) | ||
.findFirst() | ||
.map(x -> instanceDetail.getIndex() + "." + x) | ||
.get(); | ||
HashMap<String, String> metadata = new HashMap<>(); | ||
metadata.put("applicationId", applicationId); | ||
metadata.put("instanceId", applicationIndex); | ||
return (ServiceInstance) new DefaultServiceInstance(name, url, 8080, | ||
false, metadata); | ||
}) | ||
.collectList() | ||
.block(); | ||
} | ||
|
||
private boolean isInternalDomain(String url) { | ||
return url != null && url.endsWith(INTERNAL_DOMAIN); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
116 changes: 116 additions & 0 deletions
116
...ringframework/cloud/cloudfoundry/discovery/CloudFoundryAppServiceDiscoveryClientTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package org.springframework.cloud.cloudfoundry.discovery; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
|
||
import org.cloudfoundry.operations.CloudFoundryOperations; | ||
import org.cloudfoundry.operations.applications.ApplicationDetail; | ||
import org.cloudfoundry.operations.applications.InstanceDetail; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.springframework.cloud.client.DefaultServiceInstance; | ||
import org.springframework.cloud.client.ServiceInstance; | ||
import org.springframework.cloud.cloudfoundry.CloudFoundryService; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
import static org.mockito.BDDMockito.given; | ||
import static org.mockito.Mockito.mock; | ||
|
||
import reactor.core.publisher.Flux; | ||
import reactor.util.function.Tuples; | ||
|
||
/** | ||
* @author Toshiaki Maki | ||
*/ | ||
public class CloudFoundryAppServiceDiscoveryClientTest { | ||
private CloudFoundryAppServiceDiscoveryClient discoveryClient; | ||
private CloudFoundryOperations cloudFoundryOperations; | ||
private CloudFoundryService cloudFoundryService; | ||
|
||
@Before | ||
public void setUp() { | ||
this.cloudFoundryOperations = mock(CloudFoundryOperations.class); | ||
this.cloudFoundryService = mock(CloudFoundryService.class); | ||
this.discoveryClient = new CloudFoundryAppServiceDiscoveryClient( | ||
this.cloudFoundryOperations, this.cloudFoundryService, | ||
new CloudFoundryDiscoveryProperties()); | ||
} | ||
|
||
@Test | ||
public void getInstancesOneInstance() { | ||
String serviceId = "billing"; | ||
ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing1") | ||
.name("billing").instances(1).memoryLimit(1024).stack("cflinux2") | ||
.diskQuota(1024).requestedState("Running").runningInstances(1) | ||
.url("billing.apps.example.com", "billing.apps.internal").build(); | ||
given(this.cloudFoundryService.getApplicationInstances(serviceId)) | ||
.willReturn(Flux.just(Tuples.of(applicationDetail, | ||
InstanceDetail.builder().index("0").build()))); | ||
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); | ||
|
||
assertThat(instances).hasSize(1); | ||
assertThat(instances.get(0)).isEqualTo(new DefaultServiceInstance(serviceId, | ||
"0.billing.apps.internal", 8080, false, new HashMap<String, String>() { | ||
{ | ||
put("applicationId", "billing1"); | ||
put("instanceId", "0"); | ||
} | ||
})); | ||
} | ||
|
||
@Test | ||
public void getInstancesThreeInstance() { | ||
String serviceId = "billing"; | ||
ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing-id") | ||
.name("billing").instances(3).memoryLimit(1024).stack("cflinux2") | ||
.diskQuota(1024).requestedState("Running").runningInstances(3) | ||
.url("billing.apps.example.com", "billing.apps.internal").build(); | ||
given(this.cloudFoundryService.getApplicationInstances(serviceId)) | ||
.willReturn(Flux.just( | ||
Tuples.of(applicationDetail, | ||
InstanceDetail.builder().index("0").build()), | ||
Tuples.of(applicationDetail, | ||
InstanceDetail.builder().index("1").build()), | ||
Tuples.of(applicationDetail, | ||
InstanceDetail.builder().index("2").build()))); | ||
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); | ||
|
||
assertThat(instances).hasSize(3); | ||
assertThat(instances.get(0)).isEqualTo(new DefaultServiceInstance(serviceId, | ||
"0.billing.apps.internal", 8080, false, new HashMap<String, String>() { | ||
{ | ||
put("applicationId", "billing-id"); | ||
put("instanceId", "0"); | ||
} | ||
})); | ||
assertThat(instances.get(1)).isEqualTo(new DefaultServiceInstance(serviceId, | ||
"1.billing.apps.internal", 8080, false, new HashMap<String, String>() { | ||
{ | ||
put("applicationId", "billing-id"); | ||
put("instanceId", "1"); | ||
} | ||
})); | ||
assertThat(instances.get(2)).isEqualTo(new DefaultServiceInstance(serviceId, | ||
"2.billing.apps.internal", 8080, false, new HashMap<String, String>() { | ||
{ | ||
put("applicationId", "billing-id"); | ||
put("instanceId", "2"); | ||
} | ||
})); | ||
} | ||
|
||
@Test | ||
public void getInstancesEmpty() { | ||
String serviceId = "billing"; | ||
ApplicationDetail applicationDetail = ApplicationDetail.builder().id("billing1") | ||
.name("billing").instances(1).memoryLimit(1024).stack("cflinux2") | ||
.diskQuota(1024).requestedState("Running").runningInstances(1) | ||
.url("billing.apps.example.com").build(); | ||
given(this.cloudFoundryService.getApplicationInstances(serviceId)) | ||
.willReturn(Flux.just(Tuples.of(applicationDetail, | ||
InstanceDetail.builder().index("0").build()))); | ||
List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId); | ||
|
||
assertThat(instances).isEmpty(); | ||
} | ||
} |
72 changes: 72 additions & 0 deletions
72
...gframework/cloud/cloudfoundry/discovery/CloudFoundryDiscoveryClientConfigurationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
package org.springframework.cloud.cloudfoundry.discovery; | ||
|
||
import org.cloudfoundry.operations.CloudFoundryOperations; | ||
import org.junit.Test; | ||
import org.mockito.Mockito; | ||
import org.springframework.boot.autoconfigure.AutoConfigurations; | ||
import org.springframework.boot.test.context.runner.ApplicationContextRunner; | ||
import org.springframework.cloud.client.discovery.DiscoveryClient; | ||
import org.springframework.cloud.cloudfoundry.CloudFoundryService; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
import static org.assertj.core.api.Assertions.assertThat; | ||
|
||
/** | ||
* Tests for {@link CloudFoundryDiscoveryClientConfiguration}. | ||
* @author Toshiaki Maki | ||
*/ | ||
public class CloudFoundryDiscoveryClientConfigurationTest { | ||
|
||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() | ||
.withConfiguration(AutoConfigurations | ||
.of(CloudFoundryDiscoveryClientConfiguration.class)); | ||
|
||
@Test | ||
public void testDefault() { | ||
this.contextRunner.withUserConfiguration(CloudFoundryConfig.class) | ||
.run((context) -> { | ||
DiscoveryClient discoveryClient = context | ||
.getBean(DiscoveryClient.class); | ||
assertThat(discoveryClient.getClass()) | ||
.isEqualTo(CloudFoundryDiscoveryClient.class); | ||
}); | ||
} | ||
|
||
@Test | ||
public void testUseDnsTrue() { | ||
this.contextRunner.withUserConfiguration(CloudFoundryConfig.class) | ||
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=true") | ||
.run((context) -> { | ||
DiscoveryClient discoveryClient = context | ||
.getBean(DiscoveryClient.class); | ||
assertThat(discoveryClient.getClass()) | ||
.isEqualTo(CloudFoundryAppServiceDiscoveryClient.class); | ||
}); | ||
} | ||
|
||
@Test | ||
public void testUseDnsFalse() { | ||
this.contextRunner.withUserConfiguration(CloudFoundryConfig.class) | ||
.withPropertyValues("spring.cloud.cloudfoundry.discovery.use-dns=false") | ||
.run((context) -> { | ||
DiscoveryClient discoveryClient = context | ||
.getBean(DiscoveryClient.class); | ||
assertThat(discoveryClient.getClass()) | ||
.isEqualTo(CloudFoundryDiscoveryClient.class); | ||
}); | ||
} | ||
|
||
@Configuration | ||
public static class CloudFoundryConfig { | ||
@Bean | ||
public CloudFoundryOperations cloudFoundryOperations() { | ||
return Mockito.mock(CloudFoundryOperations.class); | ||
} | ||
|
||
@Bean | ||
public CloudFoundryService cloudFoundryService() { | ||
return Mockito.mock(CloudFoundryService.class); | ||
} | ||
} | ||
} |