Skip to content

cache+server: add support for ECDS Fixes #430 #431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
@@ -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,18 +69,21 @@ 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<String> TYPE_URLS =
ImmutableList.of(
CLUSTER_TYPE_URL,
ENDPOINT_TYPE_URL,
LISTENER_TYPE_URL,
ROUTE_TYPE_URL,
SECRET_TYPE_URL);
SECRET_TYPE_URL,
EXTENSION_CONFIG_TYPE_URL);
}

public static final List<ResourceType> RESOURCE_TYPES_IN_ORDER =
ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET);
ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET, EXTENSION_CONFIG);

public static final Map<String, ResourceType> TYPE_URLS_TO_RESOURCE_TYPE =
new ImmutableMap.Builder<String, ResourceType>()
@@ -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<String, Class<? extends Message>> 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 "";
}

Original file line number Diff line number Diff line change
@@ -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() {}
}
Original file line number Diff line number Diff line change
@@ -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<Listener> listeners,
Iterable<RouteConfiguration> routes,
Iterable<Secret> secrets,
Iterable<TypedExtensionConfig> 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<RouteConfiguration> routes,
String routesVersion,
Iterable<Secret> secrets,
String secretsVersion) {
String secretsVersion,
Iterable<TypedExtensionConfig> 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<Secret> secrets();

/**
* Returns all extensions config items in the ECDS payload.
*/
public abstract SnapshotResources<TypedExtensionConfig> 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<String, VersionedResource<?>> 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<String, VersionedResource<?>> 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<String> resourceNames) {
return routes().version(resourceNames);
case SECRET:
return secrets().version(resourceNames);
case EXTENSION_CONFIG:
return extensions().version(resourceNames);
default:
return "";
}
Original file line number Diff line number Diff line change
@@ -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> SECRET = VersionedResource.create(
TestResources.createSecret(SECRET_NAME),
UUID.randomUUID().toString());
private static final VersionedResource<TypedExtensionConfig> 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) ->
Original file line number Diff line number Diff line change
@@ -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<String> 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(
Loading