Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.util.function.Supplier;

import org.cloudfoundry.client.v3.Metadata;
import org.cloudfoundry.multiapps.controller.client.util.ResilientCloudOperationExecutor;
import org.cloudfoundry.multiapps.controller.client.facade.ApplicationServicesUpdateCallback;
import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClient;
import org.cloudfoundry.multiapps.controller.client.facade.CloudControllerClientImpl;
Expand Down Expand Up @@ -69,8 +68,8 @@ public void addDomain(String domainName) {
}

@Override
public void addRoute(String host, String domainName, String path) {
executeWithRetry(() -> delegate.addRoute(host, domainName, path));
public void addRoute(String host, String domainName, String path, Map<String, Object> options) {
executeWithRetry(() -> delegate.addRoute(host, domainName, path, options));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ public interface CloudControllerClient {
*
* @param host the host of the route to register
* @param domainName the domain of the route to register
* @param options the options for the route as load balancing algorithm
*/
void addRoute(String host, String domainName, String path);
void addRoute(String host, String domainName, String path, Map<String, Object> options);

/**
* Associate (provision) a service with an application.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ public void addDomain(String domainName) {
}

@Override
public void addRoute(String host, String domainName, String path) {
handleExceptions(() -> delegate.addRoute(host, domainName, path));
public void addRoute(String host, String domainName, String path, Map<String, Object> options) {
handleExceptions(() -> delegate.addRoute(host, domainName, path, options));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@
import java.util.stream.Collectors;

import org.cloudfoundry.client.v3.routes.Route;
import org.immutables.value.Value;

import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudRoute;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudDomain;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudMetadata;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudRoute;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableRouteDestination;
import org.cloudfoundry.multiapps.controller.client.facade.domain.RouteDestination;
import org.immutables.value.Value;

@Value.Immutable
public abstract class RawCloudRoute extends RawCloudEntity<CloudRoute> {
Expand Down Expand Up @@ -47,6 +46,8 @@ public CloudRoute derive() {
.url(route.getUrl())
.destinations(destinations)
.requestedProtocol(computeRequestedProtocol(destinations))
.options(route.getOptions()
.getValues())
.build();
}

Expand All @@ -56,7 +57,7 @@ private static String computeDomain(Route route) {
.isEmpty()) {
domain = domain.substring(route.getHost()
.length()
+ 1);
+ 1);
}
if (!route.getPath()
.isEmpty()) {
Expand All @@ -73,7 +74,8 @@ private List<RouteDestination> mapDestinations() {
.stream()
.map(destination -> ImmutableRouteDestination.builder()
.metadata(ImmutableCloudMetadata.builder()
.guid(UUID.fromString(destination.getDestinationId()))
.guid(UUID.fromString(
destination.getDestinationId()))
.build())
.applicationGuid(UUID.fromString(destination.getApplication()
.getApplicationId()))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package org.cloudfoundry.multiapps.controller.client.facade.domain;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.immutables.value.Value;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.cloudfoundry.multiapps.common.AllowNulls;
import org.cloudfoundry.multiapps.controller.client.facade.Nullable;
import org.immutables.value.Value;

@Value.Immutable
@JsonSerialize(as = ImmutableCloudRoute.class)
Expand All @@ -33,6 +34,9 @@ public int getAppsUsingRoute() {
@Nullable
public abstract String getRequestedProtocol();

@AllowNulls
public abstract Map<String, Object> getOptions();

@Nullable
public abstract List<RouteDestination> getDestinations();

Expand All @@ -50,7 +54,7 @@ public String toString() {

@Override
public int hashCode() {
return Objects.hash(getDomain().getName(), getHost(), getPath(), getPort());
return Objects.hash(getDomain().getName(), getHost(), getPath(), getPort(), getOptions());
}

@Override
Expand All @@ -69,7 +73,8 @@ public boolean equals(Object object) {
return thisDomain.equals(otherDomain)
&& areEmptyOrEqual(getHost(), otherRoute.getHost())
&& areEmptyOrEqual(getPath(), otherRoute.getPath())
&& Objects.equals(getPort(), otherRoute.getPort());
&& Objects.equals(getPort(), otherRoute.getPort())
&& Objects.equals(getOptions(), otherRoute.getOptions());
// @formatter:on
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public interface CloudControllerRestClient {

void addDomain(String domainName);

void addRoute(String host, String domainName, String path);
void addRoute(String host, String domainName, String path, Map<String, Object> options);

Optional<String> bindServiceInstance(String bindingName, String applicationName, String serviceInstanceName);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,11 @@
import org.cloudfoundry.client.v3.routes.InsertRouteDestinationsRequest;
import org.cloudfoundry.client.v3.routes.ListRoutesRequest;
import org.cloudfoundry.client.v3.routes.RemoveRouteDestinationsRequest;
import org.cloudfoundry.client.v3.routes.RouteOptions;
import org.cloudfoundry.client.v3.routes.RouteRelationships;
import org.cloudfoundry.client.v3.routes.RouteResource;
import org.cloudfoundry.client.v3.routes.UpdateRouteRequest;
import org.cloudfoundry.client.v3.routes.UpdateRouteResponse;
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingRequest;
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingResponse;
import org.cloudfoundry.client.v3.servicebindings.DeleteServiceBindingRequest;
Expand Down Expand Up @@ -264,10 +267,10 @@ public void addDomain(String domainName) {
}

@Override
public void addRoute(String host, String domainName, String path) {
public void addRoute(String host, String domainName, String path, Map<String, Object> options) {
assertSpaceProvided("add route for domain");
UUID domainGuid = getRequiredDomainGuid(domainName);
doAddRoute(domainGuid, host, path);
doAddRoute(domainGuid, host, path, options);
}

@Override
Expand Down Expand Up @@ -456,7 +459,7 @@ private void addRoutes(Set<CloudRoute> routes, UUID applicationGuid) {
validateDomainForRoute(route, domains);
UUID domainGuid = domains.get(route.getDomain()
.getName());
UUID routeGuid = getOrAddRoute(domainGuid, route.getHost(), route.getPath());
UUID routeGuid = getOrAddRoute(domainGuid, route.getHost(), route.getPath(), route.getOptions());
bindRoute(routeGuid, applicationGuid, route.getRequestedProtocol());
}
}
Expand Down Expand Up @@ -641,12 +644,12 @@ public void deleteOrphanedRoutes() {
@Override
public void deleteRoute(String host, String domainName, String path) {
assertSpaceProvided("delete route for domain");
UUID routeGuid = getRouteGuid(getRequiredDomainGuid(domainName), host, path);
if (routeGuid == null) {
RouteResource routeResource = getRouteResource(getRequiredDomainGuid(domainName), host, path);
if (routeResource == null) {
throw new CloudOperationException(HttpStatus.NOT_FOUND, "Not Found",
"Host " + host + " not found for domain " + domainName + ".");
}
doDeleteRoute(routeGuid);
doDeleteRoute(UUID.fromString(routeResource.getId()));
}

@Override
Expand Down Expand Up @@ -1365,7 +1368,15 @@ private boolean isRouteOutdated(UUID applicationGuid, CloudRoute currentRoute, S
if (updatedRoute.isEmpty()) {
return true;
}
return isProtocolChanged(applicationGuid, currentRoute, updatedRoute.get());
return isProtocolChanged(applicationGuid, currentRoute, updatedRoute.get())
|| isOptionsChanged(currentRoute, updatedRoute.get());
}

private boolean isOptionsChanged(CloudRoute currentRoute, CloudRoute updatedRoute) {
if (updatedRoute.getOptions() == null) {
return false;
}
return !Objects.equals(currentRoute.getOptions(), updatedRoute.getOptions());
}

private Optional<CloudRoute> findRoute(String url, Collection<CloudRoute> routes) {
Expand Down Expand Up @@ -1396,7 +1407,7 @@ private boolean isRouteUpdated(UUID applicationGuid, CloudRoute updatedRoute, Li
if (currentRoute.isEmpty()) {
return true;
}
return isProtocolChanged(applicationGuid, currentRoute.get(), updatedRoute);
return isProtocolChanged(applicationGuid, currentRoute.get(), updatedRoute) || isOptionsChanged(currentRoute.get(), updatedRoute);
}

@Override
Expand Down Expand Up @@ -1973,15 +1984,28 @@ private Destination createDestination(UUID applicationGuid, String protocol) {
.build();
}

private UUID getOrAddRoute(UUID domainGuid, String host, String path) {
UUID routeGuid = getRouteGuid(domainGuid, host, path);
if (routeGuid == null) {
routeGuid = doAddRoute(domainGuid, host, path);
private UUID getOrAddRoute(UUID domainGuid, String host, String path, Map<String, Object> options) {
RouteResource routeResource = getRouteResource(domainGuid, host, path);
if (routeResource == null) {
return doAddRoute(domainGuid, host, path, options);
}
if (!Objects.equals(routeResource.getOptions()
.getValues(), options)) {
UpdateRouteRequest request = UpdateRouteRequest.builder()
.routeId(routeResource.getId())
.options(RouteOptions.builder()
.values(options)
.build())
.build();
UpdateRouteResponse response = delegate.routesV3()
.update(request)
.block();
return UUID.fromString(response.getId());
}
return routeGuid;
return UUID.fromString(routeResource.getId());
}

private UUID doAddRoute(UUID domainGuid, String host, String path) {
private UUID doAddRoute(UUID domainGuid, String host, String path, Map<String, Object> options) {
assertSpaceProvided("add route");
CreateRouteResponse response = delegate.routesV3()
.create(CreateRouteRequest.builder()
Expand All @@ -1993,6 +2017,9 @@ private UUID doAddRoute(UUID domainGuid, String host, String path) {
.space(buildToOneRelationship(
getTargetSpaceGuid()))
.build())
.options(RouteOptions.builder()
.values(options)
.build())
.build())
.block();
return getGuid(response);
Expand Down Expand Up @@ -2454,14 +2481,14 @@ private Map<String, UUID> getDomainsFromRoutes(Set<CloudRoute> routes) {
.block();
}

private UUID getRouteGuid(UUID domainGuid, String host, String path) {
private RouteResource getRouteResource(UUID domainGuid, String host, String path) {
List<RouteResource> routeEntitiesResource = getRouteResourcesByDomainGuidHostAndPath(domainGuid, host, path).collect(
Collectors.toList())
.block();
if (CollectionUtils.isEmpty(routeEntitiesResource)) {
return null;
}
return getGuid(routeEntitiesResource.get(0));
return routeEntitiesResource.get(0);
}

private UUID getServiceBindingGuid(UUID applicationGuid, UUID serviceInstanceGuid) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
package org.cloudfoundry.multiapps.controller.client.facade.adapters;

import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.cloudfoundry.client.v3.Relationship;
import org.cloudfoundry.client.v3.ToOneRelationship;
import org.cloudfoundry.client.v3.routes.Application;
import org.cloudfoundry.client.v3.routes.Destination;
import org.cloudfoundry.client.v3.routes.Route;
import org.cloudfoundry.client.v3.routes.RouteOptions;
import org.cloudfoundry.client.v3.routes.RouteRelationships;
import org.cloudfoundry.client.v3.routes.RouteResource;
import org.junit.jupiter.api.Test;

import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudDomain;
import org.cloudfoundry.multiapps.controller.client.facade.domain.CloudRoute;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudDomain;
import org.cloudfoundry.multiapps.controller.client.facade.domain.ImmutableCloudRoute;
import org.junit.jupiter.api.Test;

class RawCloudRouteTest {

Expand Down Expand Up @@ -44,6 +45,7 @@ private static CloudRoute buildExpectedRoute() {
.path("")
.appsUsingRoute(APPS_USING_ROUTE)
.url(HOST + "." + DOMAIN_NAME)
.options(Map.of("loadbalancing", "round-robin"))
.build();
}

Expand All @@ -67,6 +69,9 @@ private static Route buildTestRoute() {
.path("")
.url(HOST + "." + DOMAIN_NAME)
.addAllDestinations(DESTINATIONS)
.options(RouteOptions.builder()
.value("loadbalancing", "round-robin")
.build())
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package org.cloudfoundry.multiapps.controller.core.helpers;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections4.MapUtils;
import org.cloudfoundry.multiapps.common.util.MapUtil;
import org.cloudfoundry.multiapps.controller.core.cf.CloudHandlerFactory;
import org.cloudfoundry.multiapps.controller.core.helpers.v2.ConfigurationReferencesResolver;
Expand Down Expand Up @@ -142,8 +144,12 @@ private void editRoutesSetTemporaryPlaceholders(DeploymentDescriptor descriptor)
Object routeValue = routeMap.get(SupportedParameters.ROUTE);
Boolean noHostname = MapUtil.parseBooleanFlag(routeMap, SupportedParameters.NO_HOSTNAME, false);
String protocol = (String) routeMap.get(SupportedParameters.ROUTE_PROTOCOL);
@SuppressWarnings("unchecked") Map<String, Object> routeOptions = (Map<String, Object>) MapUtils.getMap(routeMap,
SupportedParameters.ROUTE_OPTIONS,
Collections.emptyMap());
if (routeValue instanceof String) {
routeMap.put(SupportedParameters.ROUTE, replacePartsWithIdlePlaceholders((String) routeValue, noHostname, protocol));
routeMap.put(SupportedParameters.ROUTE,
replacePartsWithIdlePlaceholders((String) routeValue, noHostname, protocol, routeOptions));
}

if (routeMap.containsKey(SupportedParameters.NO_HOSTNAME)) {
Expand All @@ -154,8 +160,9 @@ private void editRoutesSetTemporaryPlaceholders(DeploymentDescriptor descriptor)
}
}

private String replacePartsWithIdlePlaceholders(String uriString, boolean noHostname, String protocol) {
ApplicationURI uri = new ApplicationURI(uriString, noHostname, protocol);
private String replacePartsWithIdlePlaceholders(String uriString, boolean noHostname, String protocol,
Map<String, Object> routeOptions) {
ApplicationURI uri = new ApplicationURI(uriString, noHostname, protocol, routeOptions);
uri.setDomain(IDLE_DOMAIN_PLACEHOLDER);
uri.setHost(IDLE_HOST_PLACEHOLDER);
return uri.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public class SupportedParameters {
public static final String NO_START = "no-start";
public static final String CHECK_DEPLOY_ID = "check-deploy-id";
public static final String SKIP_DEPLOY = "skip-deploy";
public static final String ROUTE_OPTIONS = "options";

public static final String REGISTER_SERVICE_URL = "register-service-url";
public static final String REGISTER_SERVICE_URL_SERVICE_NAME = "service-name";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ public CloudRoute parseIdleRouteMap(Map<String, Object> routeMap) {
}
Boolean noHostname = MapUtil.parseBooleanFlag(routeMap, SupportedParameters.NO_HOSTNAME, false);
String protocol = (String) routeMap.get(SupportedParameters.ROUTE_PROTOCOL);
return new ApplicationURI(routeString, noHostname, protocol).toCloudRoute();
Map<String, Object> routeOptions = MapUtil.parseMap(routeMap, SupportedParameters.ROUTE_OPTIONS, Collections.emptyMap());
return new ApplicationURI(routeString, noHostname, protocol, routeOptions).toCloudRoute();
}

private Set<CloudRoute> modifyLiveRoutes(Set<CloudRoute> liveRoutes) {
Expand Down
Loading
Loading