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..2f3c2bd91 100644 --- a/cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java +++ b/cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java @@ -4,6 +4,7 @@ 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.EXTENSION_CONFIG; 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; @@ -16,6 +17,7 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Filter; import io.envoyproxy.envoy.config.listener.v3.FilterChain; @@ -42,7 +44,8 @@ public enum ResourceType { ENDPOINT, LISTENER, ROUTE, - SECRET + SECRET, + EXTENSION_CONFIG } public enum ApiVersion { @@ -66,6 +69,8 @@ public static class V3 { "type.googleapis.com/envoy.config.route.v3" + ".RouteConfiguration"; public static final String SECRET_TYPE_URL = "type.googleapis.com/envoy.extensions" + ".transport_sockets.tls.v3.Secret"; + public static final String EXTENSION_CONFIG_TYPE_URL = + "type.googleapis.com/envoy.config.core.v3" + ".TypedExtensionConfig"; public static final List TYPE_URLS = ImmutableList.of( @@ -73,11 +78,12 @@ public static class V3 { ENDPOINT_TYPE_URL, LISTENER_TYPE_URL, ROUTE_TYPE_URL, - SECRET_TYPE_URL); + SECRET_TYPE_URL, + EXTENSION_CONFIG_TYPE_URL); } public static final List RESOURCE_TYPES_IN_ORDER = - ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET); + ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET, EXTENSION_CONFIG); public static final Map TYPE_URLS_TO_RESOURCE_TYPE = new ImmutableMap.Builder() @@ -86,6 +92,7 @@ public static class V3 { .put(Resources.V3.LISTENER_TYPE_URL, LISTENER) .put(Resources.V3.ROUTE_TYPE_URL, ROUTE) .put(Resources.V3.SECRET_TYPE_URL, SECRET) + .put(Resources.V3.EXTENSION_CONFIG_TYPE_URL, EXTENSION_CONFIG) .build(); public static final Map> RESOURCE_TYPE_BY_URL = @@ -95,6 +102,7 @@ public static class V3 { .put(Resources.V3.LISTENER_TYPE_URL, Listener.class) .put(Resources.V3.ROUTE_TYPE_URL, RouteConfiguration.class) .put(Resources.V3.SECRET_TYPE_URL, Secret.class) + .put(Resources.V3.EXTENSION_CONFIG_TYPE_URL, TypedExtensionConfig.class) .build(); /** @@ -123,6 +131,10 @@ public static String getResourceName(Message resource) { return ((Secret) resource).getName(); } + if (resource instanceof TypedExtensionConfig) { + return ((TypedExtensionConfig) resource).getName(); + } + return ""; } 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 1ae8865cf..8b20afbd1 100644 --- a/cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java +++ b/cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java @@ -14,6 +14,7 @@ import io.envoyproxy.envoy.config.core.v3.GrpcService; import io.envoyproxy.envoy.config.core.v3.SocketAddress; import io.envoyproxy.envoy.config.core.v3.SocketAddress.Protocol; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.endpoint.v3.Endpoint; import io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint; @@ -29,6 +30,7 @@ import io.envoyproxy.envoy.extensions.filters.http.router.v3.Router; import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager; import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.CodecType; +import io.envoyproxy.envoy.extensions.filters.network.thrift_proxy.filters.header_to_metadata.v3.HeaderToMetadata; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.Secret; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.TlsCertificate; @@ -245,5 +247,17 @@ public static Secret createSecret(String secretName) { .build(); } + /** + * Returns a new test v3 secret. + * + * @param configName name of the new config + */ + public static TypedExtensionConfig createExtensionConfig(String configName) { + return TypedExtensionConfig.newBuilder() + .setName(configName) + .setTypedConfig(Any.pack(HeaderToMetadata.getDefaultInstance())) + .build(); + } + private TestResources() {} } 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..64ac23999 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 @@ -12,6 +12,7 @@ import io.envoyproxy.controlplane.cache.SnapshotResources; import io.envoyproxy.controlplane.cache.VersionedResource; import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; @@ -44,6 +45,7 @@ public static Snapshot create( Iterable listeners, Iterable routes, Iterable secrets, + Iterable extensions, String version) { return new AutoValue_Snapshot( @@ -56,7 +58,9 @@ public static Snapshot create( SnapshotResources .create(generateSnapshotResourceIterable(routes), version), SnapshotResources - .create(generateSnapshotResourceIterable(secrets), version)); + .create(generateSnapshotResourceIterable(secrets), version), + SnapshotResources + .create(generateSnapshotResourceIterable(extensions), version)); } /** @@ -82,7 +86,9 @@ public static Snapshot create( Iterable routes, String routesVersion, Iterable secrets, - String secretsVersion) { + String secretsVersion, + Iterable extensions, + String extensionsVersion) { // TODO(snowp): add a builder alternative return new AutoValue_Snapshot( @@ -95,7 +101,9 @@ public static Snapshot create( SnapshotResources .create(generateSnapshotResourceIterable(routes), routesVersion), SnapshotResources.create(generateSnapshotResourceIterable(secrets), - secretsVersion)); + secretsVersion), + SnapshotResources.create(generateSnapshotResourceIterable(extensions), + extensionsVersion)); } /** @@ -105,7 +113,8 @@ 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 +142,11 @@ public static Snapshot createEmpty(String version) { */ public abstract SnapshotResources secrets(); + /** + * Returns all extensions config items in the ECDS payload. + */ + public abstract SnapshotResources extensions(); + /** * 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. @@ -191,6 +205,8 @@ public Map> resources(String typeUrl) { return (Map) routes().resources(); case SECRET: return (Map) secrets().resources(); + case EXTENSION_CONFIG: + return (Map) extensions().resources(); default: return ImmutableMap.of(); } @@ -213,6 +229,8 @@ public Map> versionedResources(ResourceType resourc return (Map) routes().versionedResources(); case SECRET: return (Map) secrets().versionedResources(); + case EXTENSION_CONFIG: + return (Map) extensions().versionedResources(); default: return ImmutableMap.of(); } @@ -268,6 +286,8 @@ public String version(ResourceType resourceType, List resourceNames) { return routes().version(resourceNames); case SECRET: return secrets().version(resourceNames); + case EXTENSION_CONFIG: + return extensions().version(resourceNames); default: return ""; } diff --git a/cache/src/test/java/io/envoyproxy/controlplane/cache/ResourcesTest.java b/cache/src/test/java/io/envoyproxy/controlplane/cache/ResourcesTest.java index a3c7522f2..c75471f2e 100644 --- a/cache/src/test/java/io/envoyproxy/controlplane/cache/ResourcesTest.java +++ b/cache/src/test/java/io/envoyproxy/controlplane/cache/ResourcesTest.java @@ -11,6 +11,7 @@ import com.google.protobuf.Message; import com.google.type.Color; import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; @@ -31,6 +32,7 @@ public class ResourcesTest { private static final String LISTENER_NAME = "v3listener"; private static final String ROUTE_NAME = "v3route"; private static final String SECRET_NAME = "v3secret"; + private static final String EXTENSION_CONFIG_NAME = "v3extension_config"; private static final int ENDPOINT_PORT = ThreadLocalRandom.current().nextInt(10000, 20000); private static final int LISTENER_PORT = ThreadLocalRandom.current().nextInt(20000, 30000); @@ -47,6 +49,9 @@ public class ResourcesTest { private static final VersionedResource SECRET = VersionedResource.create( TestResources.createSecret(SECRET_NAME), UUID.randomUUID().toString()); + private static final VersionedResource EXTENSION_CONFIG = VersionedResource.create( + TestResources.createExtensionConfig(EXTENSION_CONFIG_NAME), + UUID.randomUUID().toString()); @Test public void getResourceNameReturnsExpectedNameForValidResourceMessage() { @@ -56,7 +61,8 @@ public void getResourceNameReturnsExpectedNameForValidResourceMessage() { ENDPOINT, CLUSTER_NAME, LISTENER, LISTENER_NAME, ROUTE, ROUTE_NAME, - SECRET, SECRET_NAME); + SECRET, SECRET_NAME, + EXTENSION_CONFIG, EXTENSION_CONFIG_NAME); cases.forEach( (resource, expectedName) -> 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 b8654f6ba..8c123fe8d 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 @@ -16,6 +16,7 @@ import io.envoyproxy.controlplane.cache.XdsRequest; import io.envoyproxy.envoy.config.cluster.v3.Cluster; import io.envoyproxy.envoy.config.core.v3.Node; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; @@ -40,6 +41,7 @@ public class SimpleCacheTest { 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 EXTENSION_CONFIG_NAME = "extension_config0"; private static final String VERSION1 = UUID.randomUUID().toString(); private static final String VERSION2 = UUID.randomUUID().toString(); @@ -50,6 +52,7 @@ public class SimpleCacheTest { ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()), ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()), ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()), + ImmutableList.of(TypedExtensionConfig.newBuilder().setName(EXTENSION_CONFIG_NAME).build()), VERSION1); private static final Snapshot SNAPSHOT2 = Snapshot.create( @@ -58,6 +61,7 @@ public class SimpleCacheTest { ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()), ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()), ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()), + ImmutableList.of(TypedExtensionConfig.newBuilder().setName(EXTENSION_CONFIG_NAME).build()), VERSION2); private static final Snapshot MULTIPLE_RESOURCES_SNAPSHOT2 = Snapshot.create( @@ -68,6 +72,7 @@ public class SimpleCacheTest { ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()), ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()), ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()), + ImmutableList.of(TypedExtensionConfig.newBuilder().setName(EXTENSION_CONFIG_NAME).build()), VERSION2); private static void assertThatWatchIsOpenWithNoResponses(WatchAndTracker watchAndTracker) { @@ -297,7 +302,8 @@ public void successfullyWatchAllResourceTypesWithSetBeforeWatchWithRequestVersio Resources.V3.CLUSTER_TYPE_URL, Resources.V3.ENDPOINT_TYPE_URL, Resources.V3.ENDPOINT_TYPE_URL, Resources.V3.LISTENER_TYPE_URL, Resources.V3.LISTENER_TYPE_URL, ROUTE_TYPE_URL, ROUTE_TYPE_URL, - Resources.V3.SECRET_TYPE_URL, Resources.V3.SECRET_TYPE_URL); + Resources.V3.SECRET_TYPE_URL, Resources.V3.SECRET_TYPE_URL, + Resources.V3.EXTENSION_CONFIG_TYPE_URL, Resources.V3.EXTENSION_CONFIG_TYPE_URL); } @Test @@ -460,7 +466,8 @@ 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..d7bf9b166 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 @@ -2,6 +2,7 @@ import static io.envoyproxy.controlplane.cache.Resources.V3.CLUSTER_TYPE_URL; import static io.envoyproxy.controlplane.cache.Resources.V3.ENDPOINT_TYPE_URL; +import static io.envoyproxy.controlplane.cache.Resources.V3.EXTENSION_CONFIG_TYPE_URL; import static io.envoyproxy.controlplane.cache.Resources.V3.LISTENER_TYPE_URL; import static io.envoyproxy.controlplane.cache.Resources.V3.ROUTE_TYPE_URL; import static io.envoyproxy.envoy.config.core.v3.ApiVersion.V3; @@ -14,6 +15,7 @@ import io.envoyproxy.controlplane.cache.TestResources; import io.envoyproxy.controlplane.cache.VersionedResource; import io.envoyproxy.envoy.config.cluster.v3.Cluster; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; @@ -29,6 +31,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 EXTENSION_CONFIG_NAME = "extension_config0"; private static final int ENDPOINT_PORT = ThreadLocalRandom.current().nextInt(10000, 20000); private static final int LISTENER_PORT = ThreadLocalRandom.current().nextInt(20000, 30000); @@ -41,6 +44,8 @@ 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 TypedExtensionConfig + EXTENSION_CONFIG = TestResources.createExtensionConfig(EXTENSION_CONFIG_NAME); @Test public void createSingleVersionSetsResourcesCorrectly() { @@ -52,6 +57,7 @@ public void createSingleVersionSetsResourcesCorrectly() { ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), version); assertThat(snapshot.clusters().resources()) @@ -83,13 +89,15 @@ public void createSeparateVersionsSetsResourcesCorrectly() { final String listenersVersion = UUID.randomUUID().toString(); final String routesVersion = UUID.randomUUID().toString(); final String secretsVersion = UUID.randomUUID().toString(); + final String extensionsVersion = 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(SECRET), secretsVersion + ImmutableList.of(SECRET), secretsVersion, + ImmutableList.of(EXTENSION_CONFIG), extensionsVersion ); assertThat(snapshot.clusters().resources()) @@ -108,10 +116,15 @@ public void createSeparateVersionsSetsResourcesCorrectly() { .containsEntry(ROUTE_NAME, ROUTE) .hasSize(1); + assertThat(snapshot.extensions().resources()) + .containsEntry(EXTENSION_CONFIG_NAME, EXTENSION_CONFIG) + .hasSize(1); + assertThat(snapshot.clusters().version()).isEqualTo(clustersVersion); assertThat(snapshot.endpoints().version()).isEqualTo(endpointsVersion); assertThat(snapshot.listeners().version()).isEqualTo(listenersVersion); assertThat(snapshot.routes().version()).isEqualTo(routesVersion); + assertThat(snapshot.extensions().version()).isEqualTo(extensionsVersion); } @Test @@ -123,6 +136,7 @@ public void resourcesReturnsExpectedResources() { ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), UUID.randomUUID().toString()); // We have to do some lame casting to appease java's compiler, otherwise it fails to compile @@ -145,6 +159,10 @@ public void resourcesReturnsExpectedResources() { .containsEntry(ROUTE_NAME, VersionedResource.create(ROUTE)) .hasSize(1); + assertThat(snapshot.resources(EXTENSION_CONFIG_TYPE_URL)) + .containsEntry(EXTENSION_CONFIG_NAME, VersionedResource.create(EXTENSION_CONFIG)) + .hasSize(1); + String nullString = null; assertThat(snapshot.resources(nullString)).isEmpty(); assertThat(snapshot.resources("")).isEmpty(); @@ -161,12 +179,14 @@ public void versionReturnsExpectedVersion() { ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), version); assertThat(snapshot.version(CLUSTER_TYPE_URL)).isEqualTo(version); assertThat(snapshot.version(ENDPOINT_TYPE_URL)).isEqualTo(version); assertThat(snapshot.version(LISTENER_TYPE_URL)).isEqualTo(version); assertThat(snapshot.version(ROUTE_TYPE_URL)).isEqualTo(version); + assertThat(snapshot.version(EXTENSION_CONFIG_TYPE_URL)).isEqualTo(version); String nullString = null; assertThat(snapshot.resources(nullString)).isEmpty(); @@ -183,6 +203,7 @@ public void ensureConsistentReturnsWithoutExceptionForConsistentSnapshot() ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), UUID.randomUUID().toString()); snapshot.ensureConsistent(); @@ -196,6 +217,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteRefCountMismatch() { ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), UUID.randomUUID().toString()); assertThatThrownBy(snapshot1::ensureConsistent) @@ -212,6 +234,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteRefCountMismatch() { ImmutableList.of(LISTENER), ImmutableList.of(), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), UUID.randomUUID().toString()); assertThatThrownBy(snapshot2::ensureConsistent) @@ -234,6 +257,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteNamesMismatch() { ImmutableList.of(LISTENER), ImmutableList.of(ROUTE), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), UUID.randomUUID().toString()); assertThatThrownBy(snapshot1::ensureConsistent) @@ -251,6 +275,7 @@ public void ensureConsistentThrowsIfEndpointOrRouteNamesMismatch() { ImmutableList.of(LISTENER), ImmutableList.of(TestResources.createRoute(otherRouteName, CLUSTER_NAME)), ImmutableList.of(SECRET), + ImmutableList.of(EXTENSION_CONFIG), UUID.randomUUID().toString()); assertThatThrownBy(snapshot2::ensureConsistent) 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 3c3621c62..4a3bf50b4 100644 --- a/server/src/main/java/io/envoyproxy/controlplane/server/V3DiscoveryServer.java +++ b/server/src/main/java/io/envoyproxy/controlplane/server/V3DiscoveryServer.java @@ -21,6 +21,7 @@ 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.envoyproxy.envoy.service.extension.v3.ExtensionConfigDiscoveryServiceGrpc.ExtensionConfigDiscoveryServiceImplBase; import io.grpc.stub.StreamObserver; import java.util.Collection; import java.util.Collections; @@ -185,6 +186,27 @@ public StreamObserver deltaSecrets( }; } + /** + * Returns a SDS implementation that uses this server's {@link ConfigWatcher}. + */ + public ExtensionConfigDiscoveryServiceImplBase getExtensionConfigDiscoveryServiceImpl() { + return new ExtensionConfigDiscoveryServiceImplBase() { + @Override + public StreamObserver streamExtensionConfigs( + StreamObserver responseObserver) { + + return createRequestHandler(responseObserver, false, Resources.V3.EXTENSION_CONFIG_TYPE_URL); + } + + @Override + public StreamObserver deltaExtensionConfigs( + StreamObserver responseObserver) { + + return createDeltaRequestHandler(responseObserver, false, Resources.V3.EXTENSION_CONFIG_TYPE_URL); + } + }; + } + @Override protected XdsRequest wrapXdsRequest(DiscoveryRequest request) { return XdsRequest.create(request); 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..6da5279b7 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/TestMain.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/TestMain.java @@ -34,6 +34,7 @@ public static void main(String[] arg) throws IOException, InterruptedException { ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(), "1")); V3DiscoveryServer v3DiscoveryServer = new V3DiscoveryServer(cache); @@ -66,6 +67,7 @@ public static void main(String[] arg) throws IOException, InterruptedException { ImmutableList.of(), ImmutableList.of(), ImmutableList.of(), + ImmutableList.of(), "1")); server.awaitTermination(); diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsAllowDefaultEmptyEdsIT.java b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsAllowDefaultEmptyEdsIT.java index a631a566a..95274d889 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsAllowDefaultEmptyEdsIT.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerAdsAllowDefaultEmptyEdsIT.java @@ -66,6 +66,7 @@ protected void configureServerBuilder(NettyServerBuilder builder) { ImmutableList.of(listener), ImmutableList.of(route), ImmutableList.of(), + ImmutableList.of(), "1"); cache.setSnapshot(GROUP, snapshot); 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/V3DiscoveryServerTest.java b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerTest.java index 6e41b4282..a727c571c 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerTest.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerTest.java @@ -24,6 +24,7 @@ import io.envoyproxy.controlplane.server.exception.RequestException; import io.envoyproxy.envoy.config.cluster.v3.Cluster; import io.envoyproxy.envoy.config.core.v3.Node; +import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig; import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment; import io.envoyproxy.envoy.config.listener.v3.Listener; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; @@ -37,6 +38,8 @@ import io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse; import io.envoyproxy.envoy.service.endpoint.v3.EndpointDiscoveryServiceGrpc; import io.envoyproxy.envoy.service.endpoint.v3.EndpointDiscoveryServiceGrpc.EndpointDiscoveryServiceStub; +import io.envoyproxy.envoy.service.extension.v3.ExtensionConfigDiscoveryServiceGrpc; +import io.envoyproxy.envoy.service.extension.v3.ExtensionConfigDiscoveryServiceGrpc.ExtensionConfigDiscoveryServiceStub; import io.envoyproxy.envoy.service.listener.v3.ListenerDiscoveryServiceGrpc; import io.envoyproxy.envoy.service.listener.v3.ListenerDiscoveryServiceGrpc.ListenerDiscoveryServiceStub; import io.envoyproxy.envoy.service.route.v3.RouteDiscoveryServiceGrpc; @@ -75,6 +78,7 @@ public class V3DiscoveryServerTest { 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 EXTENSION_CONFIG_NAME = "extension_config0"; private static final int ENDPOINT_PORT = Ports.getAvailablePort(); private static final int LISTENER_PORT = Ports.getAvailablePort(); @@ -95,6 +99,8 @@ public class V3DiscoveryServerTest { private static final RouteConfiguration ROUTE = TestResources.createRoute(ROUTE_NAME, CLUSTER_NAME); private static final Secret SECRET = TestResources.createSecret(SECRET_NAME); + private static final TypedExtensionConfig + EXTENSION_CONFIG = TestResources.createExtensionConfig(EXTENSION_CONFIG_NAME); @Rule public final GrpcServerRule grpcServer = new GrpcServerRule().directExecutor(); @@ -140,6 +146,12 @@ public void testAggregatedHandler() throws InterruptedException { .addResourceNames(SECRET_NAME) .build()); + requestObserver.onNext(DiscoveryRequest.newBuilder() + .setNode(NODE) + .setTypeUrl(Resources.V3.EXTENSION_CONFIG_TYPE_URL) + .addResourceNames(EXTENSION_CONFIG_NAME) + .build()); + requestObserver.onCompleted(); if (!responseObserver.completedLatch.await(1, TimeUnit.SECONDS) || responseObserver.error.get()) { @@ -171,12 +183,15 @@ public void testSeparateHandlers() throws InterruptedException { grpcServer.getServiceRegistry().addService(server.getListenerDiscoveryServiceImpl()); grpcServer.getServiceRegistry().addService(server.getRouteDiscoveryServiceImpl()); grpcServer.getServiceRegistry().addService(server.getSecretDiscoveryServiceImpl()); + grpcServer.getServiceRegistry().addService(server.getExtensionConfigDiscoveryServiceImpl()); ClusterDiscoveryServiceStub clusterStub = ClusterDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); EndpointDiscoveryServiceStub endpointStub = EndpointDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); ListenerDiscoveryServiceStub listenerStub = ListenerDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); RouteDiscoveryServiceStub routeStub = RouteDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); SecretDiscoveryServiceStub secretStub = SecretDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); + ExtensionConfigDiscoveryServiceStub + extensionsStub = ExtensionConfigDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); for (String typeUrl : Resources.V3.TYPE_URLS) { MockDiscoveryResponseObserver responseObserver = new MockDiscoveryResponseObserver(); @@ -205,6 +220,10 @@ public void testSeparateHandlers() throws InterruptedException { requestObserver = secretStub.streamSecrets(responseObserver); discoveryRequestBuilder.addResourceNames(SECRET_NAME); break; + case Resources.V3.EXTENSION_CONFIG_TYPE_URL: + requestObserver = extensionsStub.streamExtensionConfigs(responseObserver); + discoveryRequestBuilder.addResourceNames(EXTENSION_CONFIG_NAME); + break; default: fail("Unsupported resource type: " + typeUrl); } @@ -372,12 +391,15 @@ public void testSeparateHandlersDefaultRequestType() throws InterruptedException grpcServer.getServiceRegistry().addService(server.getListenerDiscoveryServiceImpl()); grpcServer.getServiceRegistry().addService(server.getRouteDiscoveryServiceImpl()); grpcServer.getServiceRegistry().addService(server.getSecretDiscoveryServiceImpl()); + grpcServer.getServiceRegistry().addService(server.getExtensionConfigDiscoveryServiceImpl()); ClusterDiscoveryServiceStub clusterStub = ClusterDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); EndpointDiscoveryServiceStub endpointStub = EndpointDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); ListenerDiscoveryServiceStub listenerStub = ListenerDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); RouteDiscoveryServiceStub routeStub = RouteDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); SecretDiscoveryServiceStub secretStub = SecretDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); + ExtensionConfigDiscoveryServiceStub + extensionsStub = ExtensionConfigDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); for (String typeUrl : Resources.V3.TYPE_URLS) { MockDiscoveryResponseObserver responseObserver = new MockDiscoveryResponseObserver(); @@ -400,6 +422,9 @@ public void testSeparateHandlersDefaultRequestType() throws InterruptedException case Resources.V3.SECRET_TYPE_URL: requestObserver = secretStub.streamSecrets(responseObserver); break; + case Resources.V3.EXTENSION_CONFIG_TYPE_URL: + requestObserver = extensionsStub.streamExtensionConfigs(responseObserver); + break; default: fail("Unsupported resource type: " + typeUrl); } @@ -517,6 +542,12 @@ public void onV3StreamResponse(long streamId, DiscoveryRequest request, .addResourceNames(SECRET_NAME) .build()); + requestObserver.onNext(DiscoveryRequest.newBuilder() + .setNode(NODE) + .setTypeUrl(Resources.V3.EXTENSION_CONFIG_TYPE_URL) + .addResourceNames(EXTENSION_CONFIG_NAME) + .build()); + if (!streamRequestLatch.get().await(1, TimeUnit.SECONDS)) { fail("failed to execute onStreamRequest callback before timeout"); } @@ -567,6 +598,14 @@ public void onV3StreamResponse(long streamId, DiscoveryRequest request, .setVersionInfo(VERSION) .build()); + requestObserver.onNext(DiscoveryRequest.newBuilder() + .setNode(NODE) + .setResponseNonce("5") + .setTypeUrl(Resources.V3.EXTENSION_CONFIG_TYPE_URL) + .addResourceNames(EXTENSION_CONFIG_NAME) + .setVersionInfo(VERSION) + .build()); + if (!streamRequestLatch.get().await(1, TimeUnit.SECONDS)) { fail("failed to execute onStreamRequest callback before timeout"); } @@ -659,12 +698,15 @@ public void onV3StreamResponse(long streamId, DiscoveryRequest request, grpcServer.getServiceRegistry().addService(server.getListenerDiscoveryServiceImpl()); grpcServer.getServiceRegistry().addService(server.getRouteDiscoveryServiceImpl()); grpcServer.getServiceRegistry().addService(server.getSecretDiscoveryServiceImpl()); + grpcServer.getServiceRegistry().addService(server.getExtensionConfigDiscoveryServiceImpl()); ClusterDiscoveryServiceStub clusterStub = ClusterDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); EndpointDiscoveryServiceStub endpointStub = EndpointDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); ListenerDiscoveryServiceStub listenerStub = ListenerDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); RouteDiscoveryServiceStub routeStub = RouteDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); SecretDiscoveryServiceStub secretStub = SecretDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); + ExtensionConfigDiscoveryServiceStub + extensionsStub = ExtensionConfigDiscoveryServiceGrpc.newStub(grpcServer.getChannel()); for (String typeUrl : Resources.V3.TYPE_URLS) { MockDiscoveryResponseObserver responseObserver = new MockDiscoveryResponseObserver(); @@ -687,6 +729,9 @@ public void onV3StreamResponse(long streamId, DiscoveryRequest request, case Resources.V3.SECRET_TYPE_URL: requestObserver = secretStub.streamSecrets(responseObserver); break; + case Resources.V3.EXTENSION_CONFIG_TYPE_URL: + requestObserver = extensionsStub.streamExtensionConfigs(responseObserver); + break; default: fail("Unsupported resource type: " + typeUrl); } @@ -719,11 +764,11 @@ public void onV3StreamResponse(long streamId, DiscoveryRequest request, callbacks.assertThatNoErrors(); - assertThat(callbacks.streamCloseCount).hasValue(5); + assertThat(callbacks.streamCloseCount).hasValue(6); assertThat(callbacks.streamCloseWithErrorCount).hasValue(0); - assertThat(callbacks.streamOpenCount).hasValue(5); - assertThat(callbacks.streamRequestCount).hasValue(5); - assertThat(callbacks.streamResponseCount).hasValue(5); + assertThat(callbacks.streamOpenCount).hasValue(6); + assertThat(callbacks.streamRequestCount).hasValue(6); + assertThat(callbacks.streamResponseCount).hasValue(6); } @Test @@ -1012,6 +1057,7 @@ private static Table> createRespon .put(Resources.V3.LISTENER_TYPE_URL, VERSION, ImmutableList.of(LISTENER)) .put(Resources.V3.ROUTE_TYPE_URL, VERSION, ImmutableList.of(ROUTE)) .put(Resources.V3.SECRET_TYPE_URL, VERSION, ImmutableList.of(SECRET)) + .put(Resources.V3.EXTENSION_CONFIG_TYPE_URL, VERSION, ImmutableList.of(EXTENSION_CONFIG)) .build(); } diff --git a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerXdsDeltaResourcesIT.java b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerXdsDeltaResourcesIT.java index 15527f30b..bd595535b 100644 --- a/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerXdsDeltaResourcesIT.java +++ b/server/src/test/java/io/envoyproxy/controlplane/server/V3DiscoveryServerXdsDeltaResourcesIT.java @@ -69,6 +69,7 @@ protected void configureServerBuilder(NettyServerBuilder builder) { builder.addService(server.getEndpointDiscoveryServiceImpl()); builder.addService(server.getClusterDiscoveryServiceImpl()); builder.addService(server.getSecretDiscoveryServiceImpl()); + builder.addService(server.getExtensionConfigDiscoveryServiceImpl()); } }; 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); }