Allow to combine domains and domain properties

This commit changes the default behaviour of `domains` property -
instead of overriding `domain` it will merge values from both into a
single list.
This commit is contained in:
Alexey Nesterov
2019-10-30 17:43:53 +00:00
parent 29e34e6a6d
commit c32dd2b103
3 changed files with 149 additions and 32 deletions

View File

@@ -31,6 +31,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -227,8 +228,9 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
private Mono<String> associateHostName(String applicationId, Map<String, String> properties) {
String domain = domain(properties);
Set<String> domains = domains(properties);
String host = host(properties);
if (host == null && domain == null) {
if (host == null && domain == null && domains.isEmpty()) {
return Mono.just(applicationId);
}
@@ -236,32 +238,40 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
.getOperations(properties)
.map(cfOperations -> cfOperations.domains().list())
.flatMap(Flux::collectList)
.flatMap(domains -> getDomainId(domain, domains))
.flatMap(domainId -> Mono.zip(Mono.just(domainId), getSpaceId(properties)))
.flatMap(tupleDomainIdSpaceId -> {
String domainId = tupleDomainIdSpaceId.getT1();
String spaceId = tupleDomainIdSpaceId.getT2();
return client.routes()
.create(org.cloudfoundry.client.v2.routes.CreateRouteRequest
.builder()
.domainId(domainId)
.spaceId(spaceId)
.host(host)
.build())
.map(response -> response.getMetadata().getId())
.doOnError(error -> logger.info("Host was already associated: " + host))
.onErrorResume(e -> Mono.empty());
.map(allDomains -> Stream.concat(Stream.of(domain), domains.stream())
.map(d -> getDomainId(d, allDomains))
.collect(Collectors.toSet()))
.zipWith(getSpaceId(properties))
.flatMapMany(domainIdsWithSpaceId -> {
Set<String> uniqueDomainIds = domainIdsWithSpaceId.getT1();
String spaceId = domainIdsWithSpaceId.getT2();
return Flux.fromIterable(uniqueDomainIds).flatMap(domainId -> associateHostForDomain(applicationId, host, domainId, spaceId));
})
.flatMap(routeId ->
client.applicationsV2()
.associateRoute(AssociateApplicationRouteRequest
.builder()
.applicationId(applicationId)
.routeId(routeId)
.build()))
.then(Mono.just(applicationId));
}
private Mono<Void> associateHostForDomain(String applicationId, String host, String domainId, String spaceId) {
return client.routes()
.create(org.cloudfoundry.client.v2.routes.CreateRouteRequest
.builder()
.domainId(domainId)
.spaceId(spaceId)
.host(host)
.build())
.map(response -> response.getMetadata().getId())
.doOnError(error -> logger.info("Host was already associated: " + host))
.onErrorResume(e -> Mono.empty())
.flatMap(routeId ->
client.applicationsV2()
.associateRoute(AssociateApplicationRouteRequest
.builder()
.applicationId(applicationId)
.routeId(routeId)
.build()))
.then();
}
private Mono<String> getSpaceId(Map<String, String> properties) {
String space;
if (properties.containsKey(DeploymentProperties.TARGET_PROPERTY_KEY)) {
@@ -278,24 +288,23 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
.map(SpaceDetail::getId);
}
private Mono<String> getDomainId(String domain, List<Domain> domains) {
private String getDomainId(String domain, List<Domain> domains) {
if (domain == null) {
return getDefaultDomainId(domains);
}
return Mono.just(
domains.stream()
return domains.stream()
.filter(d -> d.getName().equals(domain))
.findFirst()
.orElseThrow(() -> new RuntimeException("Non existing domain"))
.getId());
.getId();
}
private Mono<String> getDefaultDomainId(List<Domain> domains) {
return Mono.just(domains.stream()
private String getDefaultDomainId(List<Domain> domains) {
return domains.stream()
.filter(d -> !"internal".equals(d.getType()))
.findFirst().orElseThrow(RuntimeException::new)
.getId());
.getId();
}
private Mono<GetDeploymentResponse> waitForDeploymentDeployed(String deploymentId) {
@@ -527,7 +536,7 @@ public class CloudFoundryAppDeployer implements AppDeployer, ResourceLoaderAware
}
if (!domains(deploymentProperties).isEmpty()) {
manifest.domains(domains(deploymentProperties));
domains(deploymentProperties).forEach(manifest::domain);
}
if (getDockerImage(appResource) == null) {

View File

@@ -340,7 +340,7 @@ class CloudFoundryAppDeployerTest {
.healthCheckType(ApplicationHealthCheck.PORT)
.healthCheckHttpEndpoint("/healthcheck2")
.buildpack("buildpack2")
.domains("default-domain", "domain2")
.domains("domain1", "default-domain", "domain2")
.host("host2")
.noRoute(true)
.build();

View File

@@ -362,6 +362,78 @@ class CloudFoundryAppDeployerUpdateApplicationTest {
.build());
}
@Test
void updateAppWithHostAndMergedDomains() {
when(applicationsV2.update(any()))
.thenReturn(Mono.just(UpdateApplicationResponse.builder().build()));
when(spaces.get(any())).thenReturn(
Mono.just(
SpaceDetail.builder()
.id("space-id")
.name("space-name")
.organization("org-name")
.build()));
mockDomainsAndRoutes();
Map<String, String> properties = new HashMap<>();
properties.put("host", "my.host");
properties.put("domain", "my.domain.com");
properties.put("domains", "my.domain.internal.com,my.domain.default.com");
UpdateApplicationRequest request =
UpdateApplicationRequest
.builder()
.name(APP_NAME)
.path(APP_PATH)
.properties(properties)
.build();
StepVerifier.create(appDeployer.update(request))
.assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME))
.verifyComplete();
verifyRouteCreatedAndMapped("myDomainComId", "my.host", "space-id", "app-id");
verifyRouteCreatedAndMapped("myDomainInternalId", "my.host", "space-id", "app-id");
verifyRouteCreatedAndMapped("myDomainDefaultId", "my.host", "space-id", "app-id");
}
@Test
void updateAppWithHostAndDomains() {
when(applicationsV2.update(any()))
.thenReturn(Mono.just(UpdateApplicationResponse.builder().build()));
when(spaces.get(any())).thenReturn(
Mono.just(
SpaceDetail.builder()
.id("space-id")
.name("space-name")
.organization("org-name")
.build()));
mockDomainsAndRoutes();
Map<String, String> properties = new HashMap<>();
properties.put("host", "my.host");
properties.put("domains", "my.domain.internal.com,my.domain.default.com");
UpdateApplicationRequest request =
UpdateApplicationRequest
.builder()
.name(APP_NAME)
.path(APP_PATH)
.properties(properties)
.build();
StepVerifier.create(appDeployer.update(request))
.assertNext(response -> assertThat(response.getName()).isEqualTo(APP_NAME))
.verifyComplete();
verifyRouteCreatedAndMapped("myDomainInternalId", "my.host", "space-id", "app-id");
verifyRouteCreatedAndMapped("myDomainDefaultId", "my.host", "space-id", "app-id");
}
@Test
void updateAppWithHostAndNoDomain() {
when(applicationsV2.update(any()))
@@ -558,6 +630,42 @@ class CloudFoundryAppDeployerUpdateApplicationTest {
.build();
}
private void verifyRouteCreatedAndMapped(String domainId, String host, String spaceId, String appId) {
verify(routes).create(
CreateRouteRequest.builder()
.domainId(domainId)
.spaceId(spaceId)
.host(host)
.build());
verify(applicationsV2).associateRoute(
AssociateApplicationRouteRequest
.builder()
.applicationId(appId)
.routeId(getRouteIdForDomain(domainId))
.build());
}
private String getRouteIdForDomain(String domainId) {
return domainId + "-route";
}
private void mockDomainsAndRoutes() {
when(domains.list()).thenReturn(getDomains());
when(routes.create(any()))
.thenAnswer(invocation -> {
CreateRouteRequest createRouteRequest = invocation.getArgument(0);
return Mono.just(
CreateRouteResponse.builder()
.metadata(Metadata
.builder()
.id(getRouteIdForDomain(createRouteRequest.getDomainId()))
.build()).build());
});
when(applicationsV2.associateRoute(any()))
.thenReturn(Mono.empty());
}
private static Lifecycle createLifecycle() {
return Lifecycle.builder().data(BuildpackData.builder().build()).type(LifecycleType.BUILDPACK).build();
}