diff --git a/api/src/main/proto/envoy/config/route/v3/route.proto b/api/src/main/proto/envoy/config/route/v3/route.proto index c953e7803..e222088da 100644 --- a/api/src/main/proto/envoy/config/route/v3/route.proto +++ b/api/src/main/proto/envoy/config/route/v3/route.proto @@ -36,12 +36,12 @@ message RouteConfiguration { // An array of virtual hosts that make up the route table. repeated VirtualHost virtual_hosts = 2; - // An array of virtual hosts will be dynamically loaded via the VHDS API. - // Both *virtual_hosts* and *vhds* fields will be used when present. *virtual_hosts* can be used - // for a base routing table or for infrequently changing virtual hosts. *vhds* is used for - // on-demand discovery of virtual hosts. The contents of these two fields will be merged to - // generate a routing table for a given RouteConfiguration, with *vhds* derived configuration - // taking precedence. +// An array of virtual hosts will be dynamically loaded via the VHDS API. +// Both *virtual_hosts* and *vhds* fields will be used when present. *virtual_hosts* can be used +// for a base routing table or for infrequently changing virtual hosts. *vhds* is used for +// on-demand discovery of virtual hosts. The contents of these two fields will be merged to +// generate a routing table for a given RouteConfiguration, with *vhds* derived configuration +// taking precedence. Vhds vhds = 9; // Optionally specifies a list of HTTP headers that the connection manager diff --git a/cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java b/cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java index b405005aa..b5311d8d6 100644 --- a/cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java +++ b/cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java @@ -2,11 +2,6 @@ import static com.google.common.base.Strings.isNullOrEmpty; import static io.envoyproxy.controlplane.cache.Resources.ApiVersion.V3; -import static io.envoyproxy.controlplane.cache.Resources.ResourceType.CLUSTER; -import static io.envoyproxy.controlplane.cache.Resources.ResourceType.ENDPOINT; -import static io.envoyproxy.controlplane.cache.Resources.ResourceType.LISTENER; -import static io.envoyproxy.controlplane.cache.Resources.ResourceType.ROUTE; -import static io.envoyproxy.controlplane.cache.Resources.ResourceType.SECRET; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -21,6 +16,7 @@ import io.envoyproxy.envoy.config.listener.v3.FilterChain; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; +import io.envoyproxy.envoy.config.route.v3.VirtualHost; import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.RouteSpecifierCase; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.Secret; @@ -42,6 +38,7 @@ public enum ResourceType { ENDPOINT, LISTENER, ROUTE, + VIRTUAL_HOST, SECRET } @@ -64,6 +61,8 @@ public static class V3 { "type.googleapis.com/envoy.config.listener.v3" + ".Listener"; public static final String ROUTE_TYPE_URL = "type.googleapis.com/envoy.config.route.v3" + ".RouteConfiguration"; + public static final String VIRTUAL_HOST_TYPE_URL = + "type.googleapis.com/envoy.config.route.v3" + ".VirtualHost"; public static final String SECRET_TYPE_URL = "type.googleapis.com/envoy.extensions" + ".transport_sockets.tls.v3.Secret"; @@ -73,19 +72,26 @@ public static class V3 { ENDPOINT_TYPE_URL, LISTENER_TYPE_URL, ROUTE_TYPE_URL, + VIRTUAL_HOST_TYPE_URL, SECRET_TYPE_URL); } public static final List RESOURCE_TYPES_IN_ORDER = - ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET); + ImmutableList.of(ResourceType.CLUSTER, + ResourceType.ENDPOINT, + ResourceType.LISTENER, + ResourceType.ROUTE, + ResourceType.VIRTUAL_HOST, + ResourceType.SECRET); public static final Map TYPE_URLS_TO_RESOURCE_TYPE = new ImmutableMap.Builder() - .put(Resources.V3.CLUSTER_TYPE_URL, CLUSTER) - .put(Resources.V3.ENDPOINT_TYPE_URL, ENDPOINT) - .put(Resources.V3.LISTENER_TYPE_URL, LISTENER) - .put(Resources.V3.ROUTE_TYPE_URL, ROUTE) - .put(Resources.V3.SECRET_TYPE_URL, SECRET) + .put(Resources.V3.CLUSTER_TYPE_URL, ResourceType.CLUSTER) + .put(Resources.V3.ENDPOINT_TYPE_URL, ResourceType.ENDPOINT) + .put(Resources.V3.LISTENER_TYPE_URL, ResourceType.LISTENER) + .put(Resources.V3.ROUTE_TYPE_URL, ResourceType.ROUTE) + .put(Resources.V3.VIRTUAL_HOST_TYPE_URL, ResourceType.VIRTUAL_HOST) + .put(Resources.V3.SECRET_TYPE_URL, ResourceType.SECRET) .build(); public static final Map> RESOURCE_TYPE_BY_URL = @@ -94,6 +100,7 @@ public static class V3 { .put(Resources.V3.ENDPOINT_TYPE_URL, ClusterLoadAssignment.class) .put(Resources.V3.LISTENER_TYPE_URL, Listener.class) .put(Resources.V3.ROUTE_TYPE_URL, RouteConfiguration.class) + .put(Resources.V3.VIRTUAL_HOST_TYPE_URL, VirtualHost.class) .put(Resources.V3.SECRET_TYPE_URL, Secret.class) .build(); @@ -119,6 +126,10 @@ public static String getResourceName(Message resource) { return ((RouteConfiguration) resource).getName(); } + if (resource instanceof VirtualHost) { + return ((VirtualHost) resource).getName(); + } + if (resource instanceof Secret) { return ((Secret) resource).getName(); } diff --git a/cache/src/main/java/io/envoyproxy/controlplane/cache/SnapshotResources.java b/cache/src/main/java/io/envoyproxy/controlplane/cache/SnapshotResources.java index f270ada2a..d2c3898dd 100644 --- a/cache/src/main/java/io/envoyproxy/controlplane/cache/SnapshotResources.java +++ b/cache/src/main/java/io/envoyproxy/controlplane/cache/SnapshotResources.java @@ -2,6 +2,7 @@ import com.google.auto.value.AutoValue; import com.google.protobuf.Message; + import java.util.List; import java.util.Map; import java.util.stream.Collector; @@ -21,7 +22,7 @@ public static SnapshotResources create( Iterable resources, String version) { ResourceMapBuilder resourcesMapBuilder = createResourcesMap(resources); - return new AutoValue_SnapshotResources<>( + return new io.envoyproxy.controlplane.cache.AutoValue_SnapshotResources<>( resourcesMapBuilder.getVersionedResources(), resourcesMapBuilder.getResources(), (r) -> version @@ -40,7 +41,7 @@ public static SnapshotResources create( Iterable> resources, ResourceVersionResolver versionResolver) { ResourceMapBuilder resourcesMapBuilder = createResourcesMap(resources); - return new AutoValue_SnapshotResources<>( + return new io.envoyproxy.controlplane.cache.AutoValue_SnapshotResources<>( resourcesMapBuilder.getVersionedResources(), resourcesMapBuilder.getResources(), versionResolver); diff --git a/cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java b/cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java index cc877c344..9b1cac2df 100644 --- a/cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java +++ b/cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java @@ -24,6 +24,7 @@ import io.envoyproxy.envoy.config.route.v3.RouteAction; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; import io.envoyproxy.envoy.config.route.v3.RouteMatch; +import io.envoyproxy.envoy.config.route.v3.Vhds; import io.envoyproxy.envoy.config.route.v3.VirtualHost; import io.envoyproxy.envoy.extensions.filters.http.router.v3.Router; import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; @@ -31,6 +32,7 @@ import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.Secret; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.TlsCertificate; + /** * {@code TestResources} provides helper methods for generating resource messages for testing. It is * not intended to be used in production code. @@ -209,6 +211,34 @@ public static Listener createListener( .build(); } + /** + * Returns a new test v3 route. + * + * @param routeName name of the new route + */ + public static RouteConfiguration createVhdsRoute(String routeName) { + + ApiVersion adsTransportVersion = ApiVersion.V3; + + ConfigSource edsSource = + ConfigSource.newBuilder() + .setResourceApiVersion(ApiVersion.V3) + .setApiConfigSource( + ApiConfigSource.newBuilder() + .setTransportApiVersion(adsTransportVersion) + .setApiType(ApiConfigSource.ApiType.DELTA_GRPC) + .addGrpcServices( + GrpcService.newBuilder() + .setEnvoyGrpc( + GrpcService.EnvoyGrpc.newBuilder() + .setClusterName(XDS_CLUSTER)))) + .build(); + + return RouteConfiguration.newBuilder() + .setVhds(Vhds.newBuilder().setConfigSource(edsSource).build()) + .setName(routeName).build(); + } + /** * Returns a new test v3 route. * @@ -229,6 +259,22 @@ public static RouteConfiguration createRoute(String routeName, String clusterNam .build(); } + /** + * Returns a new Virtual Host. + * + * @param name Virtual host name + * @param domain domain name + */ + public static VirtualHost createVirtualHost(String name, String domain) { + return VirtualHost.newBuilder() + .setName(name) + .addDomains(domain) + .addRoutes( + Route.newBuilder() + .setMatch(RouteMatch.newBuilder().setPrefix("/"))) + .build(); + } + /** * Returns a new test v3 secret. * diff --git a/cache/src/main/java/io/envoyproxy/controlplane/cache/v3/Snapshot.java b/cache/src/main/java/io/envoyproxy/controlplane/cache/v3/Snapshot.java index 97f0e0abf..804542c5d 100644 --- a/cache/src/main/java/io/envoyproxy/controlplane/cache/v3/Snapshot.java +++ b/cache/src/main/java/io/envoyproxy/controlplane/cache/v3/Snapshot.java @@ -15,12 +15,14 @@ import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; +import io.envoyproxy.envoy.config.route.v3.VirtualHost; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.Secret; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; + /** * {@code Snapshot} is a data class that contains an internally consistent snapshot of v3 xDS resources. Snapshots * should have distinct versions per node group. @@ -43,10 +45,13 @@ public static Snapshot create( Iterable endpoints, Iterable listeners, Iterable routes, + Iterable virtualHosts, Iterable secrets, + + String version) { - return new AutoValue_Snapshot( + return new io.envoyproxy.controlplane.cache.v3.AutoValue_Snapshot( SnapshotResources .create(generateSnapshotResourceIterable(clusters), version), SnapshotResources @@ -56,7 +61,9 @@ public static Snapshot create( SnapshotResources .create(generateSnapshotResourceIterable(routes), version), SnapshotResources - .create(generateSnapshotResourceIterable(secrets), version)); + .create(generateSnapshotResourceIterable(secrets), version), + SnapshotResources + .create(generateSnapshotResourceIterable(virtualHosts), version)); } /** @@ -81,11 +88,13 @@ public static Snapshot create( String listenersVersion, Iterable routes, String routesVersion, + Iterable virtualHosts, + String virtualHostsVersion, Iterable secrets, String secretsVersion) { // TODO(snowp): add a builder alternative - return new AutoValue_Snapshot( + return new io.envoyproxy.controlplane.cache.v3.AutoValue_Snapshot( SnapshotResources.create(generateSnapshotResourceIterable(clusters), clustersVersion), SnapshotResources.create(generateSnapshotResourceIterable(endpoints), @@ -94,6 +103,8 @@ public static Snapshot create( listenersVersion), SnapshotResources .create(generateSnapshotResourceIterable(routes), routesVersion), + SnapshotResources + .create(generateSnapshotResourceIterable(virtualHosts), virtualHostsVersion), SnapshotResources.create(generateSnapshotResourceIterable(secrets), secretsVersion)); } @@ -105,7 +116,7 @@ public static Snapshot create( */ public static Snapshot createEmpty(String version) { return create(Collections.emptySet(), Collections.emptySet(), - Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), version); + Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), version); } /** @@ -133,6 +144,8 @@ public static Snapshot createEmpty(String version) { */ public abstract SnapshotResources secrets(); + public abstract SnapshotResources virtualHosts(); + /** * Asserts that all dependent resources are included in the snapshot. All EDS resources are listed by name in CDS * resources, and all RDS resources are listed by name in LDS resources. @@ -189,6 +202,8 @@ public Map> resources(String typeUrl) { return (Map) listeners().resources(); case ROUTE: return (Map) routes().resources(); + case VIRTUAL_HOST: + return (Map) virtualHosts().resources(); case SECRET: return (Map) secrets().resources(); default: @@ -211,6 +226,8 @@ public Map> versionedResources(ResourceType resourc return (Map) listeners().versionedResources(); case ROUTE: return (Map) routes().versionedResources(); + case VIRTUAL_HOST: + return (Map) virtualHosts().versionedResources(); case SECRET: return (Map) secrets().versionedResources(); default: @@ -266,6 +283,8 @@ public String version(ResourceType resourceType, List resourceNames) { return listeners().version(resourceNames); case ROUTE: return routes().version(resourceNames); + case VIRTUAL_HOST: + return virtualHosts().version(resourceNames); case SECRET: return secrets().version(resourceNames); default: diff --git a/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SimpleCacheTest.java b/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SimpleCacheTest.java index a5de127ed..dee15795d 100644 --- a/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SimpleCacheTest.java +++ b/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SimpleCacheTest.java @@ -11,6 +11,7 @@ import io.envoyproxy.controlplane.cache.Resources; import io.envoyproxy.controlplane.cache.Response; import io.envoyproxy.controlplane.cache.StatusInfo; +import io.envoyproxy.controlplane.cache.TestResources; import io.envoyproxy.controlplane.cache.VersionedResource; import io.envoyproxy.controlplane.cache.Watch; import io.envoyproxy.controlplane.cache.XdsRequest; @@ -49,7 +50,9 @@ public class SimpleCacheTest { ImmutableList.of(ClusterLoadAssignment.getDefaultInstance()), ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()), ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()), + ImmutableList.of(TestResources.createVirtualHost("v1", "a")), ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()), + VERSION1); private static final Snapshot SNAPSHOT2 = Snapshot.create( @@ -57,6 +60,8 @@ public class SimpleCacheTest { ImmutableList.of(ClusterLoadAssignment.getDefaultInstance()), ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()), ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()), + ImmutableList.of(TestResources.createVirtualHost("v1", "a")), + ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()), VERSION2); @@ -67,6 +72,8 @@ public class SimpleCacheTest { ClusterLoadAssignment.newBuilder().setClusterName(SECONDARY_CLUSTER_NAME).build()), ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()), ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()), + ImmutableList.of(TestResources.createVirtualHost("v1","a")), + ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()), VERSION2); @@ -429,7 +436,13 @@ public void watchesAreReleasedAfterCancel() { public void watchIsLeftOpenIfNotRespondedImmediately() { SimpleCache cache = new SimpleCache<>(new SingleNodeGroup()); cache.setSnapshot(SingleNodeGroup.GROUP, Snapshot.create( - ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), VERSION1)); + ImmutableList.of(), + ImmutableList.of(), + ImmutableList.of(), + ImmutableList.of(), + ImmutableList.of(), + ImmutableList.of(), + VERSION1)); ResponseTracker responseTracker = new ResponseTracker(); Watch watch = cache.createWatch( diff --git a/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SnapshotTest.java b/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SnapshotTest.java index d40b02bd6..0165b9617 100644 --- a/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SnapshotTest.java +++ b/cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SnapshotTest.java @@ -17,6 +17,7 @@ import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; +import io.envoyproxy.envoy.config.route.v3.VirtualHost; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.Secret; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -29,6 +30,7 @@ public class SnapshotTest { private static final String LISTENER_NAME = "listener0"; private static final String ROUTE_NAME = "route0"; private static final String SECRET_NAME = "secret0"; + private static final String VIRTUAL_HOST_NAME = "virtual0"; private static final int ENDPOINT_PORT = ThreadLocalRandom.current().nextInt(10000, 20000); private static final int LISTENER_PORT = ThreadLocalRandom.current().nextInt(20000, 30000); @@ -41,6 +43,7 @@ public class SnapshotTest { private static final RouteConfiguration ROUTE = TestResources.createRoute(ROUTE_NAME, CLUSTER_NAME); private static final Secret SECRET = TestResources.createSecret(SECRET_NAME); + private static final VirtualHost VIRTUAL_HOST = TestResources.createVirtualHost(VIRTUAL_HOST_NAME, "a"); @Test public void createSingleVersionSetsResourcesCorrectly() { @@ -51,6 +54,7 @@ public void createSingleVersionSetsResourcesCorrectly() { ImmutableList.of(ENDPOINT), ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), version); @@ -83,13 +87,16 @@ public void createSeparateVersionsSetsResourcesCorrectly() { final String listenersVersion = UUID.randomUUID().toString(); final String routesVersion = UUID.randomUUID().toString(); final String secretsVersion = UUID.randomUUID().toString(); + final String virtualHostsVersion = UUID.randomUUID().toString(); Snapshot snapshot = Snapshot.create( ImmutableList.of(CLUSTER), clustersVersion, ImmutableList.of(ENDPOINT), endpointsVersion, ImmutableList.of(LISTENER), listenersVersion, ImmutableList.of(ROUTE), routesVersion, + ImmutableList.of(VIRTUAL_HOST), virtualHostsVersion, ImmutableList.of(SECRET), secretsVersion + ); assertThat(snapshot.clusters().resources()) @@ -122,6 +129,7 @@ public void resourcesReturnsExpectedResources() { ImmutableList.of(ENDPOINT), ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), UUID.randomUUID().toString()); @@ -160,6 +168,7 @@ public void versionReturnsExpectedVersion() { ImmutableList.of(ENDPOINT), ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), version); @@ -182,6 +191,7 @@ public void ensureConsistentReturnsWithoutExceptionForConsistentSnapshot() ImmutableList.of(ENDPOINT), ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), UUID.randomUUID().toString()); @@ -195,6 +205,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteRefCountMismatch() { ImmutableList.of(), ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), UUID.randomUUID().toString()); @@ -211,6 +222,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteRefCountMismatch() { ImmutableList.of(ENDPOINT), ImmutableList.of(LISTENER), ImmutableList.of(), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), UUID.randomUUID().toString()); @@ -233,6 +245,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteNamesMismatch() { ImmutableList.of(TestResources.createEndpoint(otherClusterName, ENDPOINT_PORT)), ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), UUID.randomUUID().toString()); @@ -250,6 +263,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteNamesMismatch() { ImmutableList.of(ENDPOINT), ImmutableList.of(LISTENER), ImmutableList.of(TestResources.createRoute(otherRouteName, CLUSTER_NAME)), + ImmutableList.of(VIRTUAL_HOST), ImmutableList.of(SECRET), UUID.randomUUID().toString()); diff --git a/server/src/main/java/io/envoyproxy/controlplane/server/V3DiscoveryServer.java b/server/src/main/java/io/envoyproxy/controlplane/server/V3DiscoveryServer.java index 56347eaaf..ca8059a8f 100644 --- a/server/src/main/java/io/envoyproxy/controlplane/server/V3DiscoveryServer.java +++ b/server/src/main/java/io/envoyproxy/controlplane/server/V3DiscoveryServer.java @@ -4,6 +4,7 @@ import static io.envoyproxy.envoy.service.endpoint.v3.EndpointDiscoveryServiceGrpc.EndpointDiscoveryServiceImplBase; import static io.envoyproxy.envoy.service.listener.v3.ListenerDiscoveryServiceGrpc.ListenerDiscoveryServiceImplBase; import static io.envoyproxy.envoy.service.route.v3.RouteDiscoveryServiceGrpc.RouteDiscoveryServiceImplBase; +import static io.envoyproxy.envoy.service.route.v3.VirtualHostDiscoveryServiceGrpc.VirtualHostDiscoveryServiceImplBase; import static io.envoyproxy.envoy.service.secret.v3.SecretDiscoveryServiceGrpc.SecretDiscoveryServiceImplBase; import com.google.common.base.Preconditions; @@ -14,13 +15,16 @@ import io.envoyproxy.controlplane.cache.XdsRequest; import io.envoyproxy.controlplane.server.serializer.DefaultProtoResourcesSerializer; import io.envoyproxy.controlplane.server.serializer.ProtoResourcesSerializer; + import io.envoyproxy.envoy.service.cluster.v3.ClusterDiscoveryServiceGrpc.ClusterDiscoveryServiceImplBase; + import io.envoyproxy.envoy.service.discovery.v3.DeltaDiscoveryRequest; import io.envoyproxy.envoy.service.discovery.v3.DeltaDiscoveryResponse; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest; import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; import io.envoyproxy.envoy.service.discovery.v3.Resource; import io.grpc.stub.StreamObserver; + import java.util.Collection; import java.util.Collections; import java.util.List; @@ -167,6 +171,11 @@ public StreamObserver streamSecrets( return createRequestHandler(responseObserver, false, Resources.V3.SECRET_TYPE_URL); } + /** + * Returns delta Secrets. + * + * @param responseObserver Stream observer + */ @Override public StreamObserver deltaSecrets( StreamObserver responseObserver) { @@ -176,6 +185,21 @@ public StreamObserver deltaSecrets( }; } + /** + * Returns VHDS implementation that uses this server. + */ + public VirtualHostDiscoveryServiceImplBase getVirtualHostDiscoveryServiceImpl() { + return new VirtualHostDiscoveryServiceImplBase() { + + @Override + public StreamObserver deltaVirtualHosts( + StreamObserver responseObserver) { + + return createDeltaRequestHandler(responseObserver, false, Resources.V3.VIRTUAL_HOST_TYPE_URL); + } + }; + } + @Override protected XdsRequest wrapXdsRequest(DiscoveryRequest request) { return XdsRequest.create(request); diff --git a/server/src/main/java/io/envoyproxy/controlplane/server/XdsDeltaDiscoveryRequestStreamObserver.java b/server/src/main/java/io/envoyproxy/controlplane/server/XdsDeltaDiscoveryRequestStreamObserver.java index 01a424778..505c33f9c 100644 --- a/server/src/main/java/io/envoyproxy/controlplane/server/XdsDeltaDiscoveryRequestStreamObserver.java +++ b/server/src/main/java/io/envoyproxy/controlplane/server/XdsDeltaDiscoveryRequestStreamObserver.java @@ -36,7 +36,8 @@ public class XdsDeltaDiscoveryRequestStreamObserver extends DeltaDiscov this.pendingResources = new HashSet<>(); Resources.ResourceType resourceType = Resources.TYPE_URLS_TO_RESOURCE_TYPE.get(defaultTypeUrl); this.isWildcard = Resources.ResourceType.CLUSTER.equals(resourceType) - || Resources.ResourceType.LISTENER.equals(resourceType); + || Resources.ResourceType.LISTENER.equals(resourceType) + || Resources.ResourceType.VIRTUAL_HOST.equals(resourceType); this.responses = new ConcurrentHashMap<>(); } diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/TestMain.java b/server/src/test/java/io/envoyproxy/controlplane/server/TestMain.java index 713ff1294..86d712eab 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/TestMain.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/TestMain.java @@ -32,18 +32,21 @@ public static void main(String[] arg) throws IOException, InterruptedException { "cluster0", "127.0.0.1", 1234, Cluster.DiscoveryType.STATIC)), ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(TestResources.createVhdsRoute("name1")), ImmutableList.of(), ImmutableList.of(), "1")); + V3DiscoveryServer v3DiscoveryServer = new V3DiscoveryServer(cache); - ServerBuilder builder = + ServerBuilder builder = NettyServerBuilder.forPort(12345) .addService(v3DiscoveryServer.getAggregatedDiscoveryServiceImpl()) .addService(v3DiscoveryServer.getClusterDiscoveryServiceImpl()) .addService(v3DiscoveryServer.getEndpointDiscoveryServiceImpl()) .addService(v3DiscoveryServer.getListenerDiscoveryServiceImpl()) + .addService(v3DiscoveryServer.getVirtualHostDiscoveryServiceImpl()) .addService(v3DiscoveryServer.getRouteDiscoveryServiceImpl()); Server server = builder.build(); @@ -64,6 +67,7 @@ public static void main(String[] arg) throws IOException, InterruptedException { "cluster1", "127.0.0.1", 1235, Cluster.DiscoveryType.STATIC)), ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(TestResources.createVhdsRoute("name2")), ImmutableList.of(), ImmutableList.of(), "1")); diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/V3DeltaDiscoveryServerCallbacks.java b/server/src/test/java/io/envoyproxy/controlplane/server/V3DeltaDiscoveryServerCallbacks.java index fdb008056..e57308979 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/V3DeltaDiscoveryServerCallbacks.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/V3DeltaDiscoveryServerCallbacks.java @@ -21,8 +21,8 @@ public class V3DeltaDiscoveryServerCallbacks implements DiscoveryServerCallbacks /** - * Returns an implementation of DiscoveryServerCallbacks that throws if it sees a nod-delta v3 request, - * and counts down on provided latches in response to certain events. + * Returns an implementation of DiscoveryServerCallbacks that throws if it sees a v2 request, and counts down on + * provided latches in response to certain events. * * @param onStreamOpenLatch latch to call countDown() on when a v3 stream is opened. * @param onStreamRequestLatch latch to call countDown() on when a v3 request is seen. diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsWarmingClusterIT.java b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsWarmingClusterIT.java index 26eeceb69..cff099ebe 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsWarmingClusterIT.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsWarmingClusterIT.java @@ -196,6 +196,8 @@ private static Snapshot createSnapshotWithNotWorkingCluster(boolean ads, ImmutableList.of(route), "2", ImmutableList.of(), + "2", + ImmutableList.of(), "2"); } diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/V3TestSnapshots.java b/server/src/test/java/io/envoyproxy/controlplane/server/V3TestSnapshots.java index 44980eea2..8174e1e94 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/V3TestSnapshots.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/V3TestSnapshots.java @@ -37,6 +37,7 @@ static Snapshot createSnapshot( ImmutableList.of(listener), ImmutableList.of(route), ImmutableList.of(), + ImmutableList.of(), version); } @@ -80,6 +81,7 @@ private static Snapshot createSnapshotNoEds( ImmutableList.of(listener), ImmutableList.of(route), ImmutableList.of(), + ImmutableList.of(), version); }