Skip to content

Commit d64dbf1

Browse files
author
Anton Kanugalawattage
committed
feature: ecds
1 parent 7a2559a commit d64dbf1

7 files changed

Lines changed: 241 additions & 10 deletions

File tree

‎cache/src/main/java/io/envoyproxy/controlplane/cache/Resources.java‎

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static io.envoyproxy.controlplane.cache.Resources.ApiVersion.V3;
55
import static io.envoyproxy.controlplane.cache.Resources.ResourceType.CLUSTER;
66
import static io.envoyproxy.controlplane.cache.Resources.ResourceType.ENDPOINT;
7+
import static io.envoyproxy.controlplane.cache.Resources.ResourceType.EXTENSION_CONFIG;
78
import static io.envoyproxy.controlplane.cache.Resources.ResourceType.LISTENER;
89
import static io.envoyproxy.controlplane.cache.Resources.ResourceType.ROUTE;
910
import static io.envoyproxy.controlplane.cache.Resources.ResourceType.SECRET;
@@ -16,6 +17,7 @@
1617
import com.google.protobuf.InvalidProtocolBufferException;
1718
import com.google.protobuf.Message;
1819
import io.envoyproxy.envoy.config.cluster.v3.Cluster;
20+
import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig;
1921
import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment;
2022
import io.envoyproxy.envoy.config.listener.v3.Filter;
2123
import io.envoyproxy.envoy.config.listener.v3.FilterChain;
@@ -42,7 +44,8 @@ public enum ResourceType {
4244
ENDPOINT,
4345
LISTENER,
4446
ROUTE,
45-
SECRET
47+
SECRET,
48+
EXTENSION_CONFIG
4649
}
4750

4851
public enum ApiVersion {
@@ -66,18 +69,21 @@ public static class V3 {
6669
"type.googleapis.com/envoy.config.route.v3" + ".RouteConfiguration";
6770
public static final String SECRET_TYPE_URL =
6871
"type.googleapis.com/envoy.extensions" + ".transport_sockets.tls.v3.Secret";
72+
public static final String EXTENSION_CONFIG_TYPE_URL =
73+
"type.googleapis.com/envoy.config.core.v3" + ".TypedExtensionConfig";
6974

7075
public static final List<String> TYPE_URLS =
7176
ImmutableList.of(
7277
CLUSTER_TYPE_URL,
7378
ENDPOINT_TYPE_URL,
7479
LISTENER_TYPE_URL,
7580
ROUTE_TYPE_URL,
76-
SECRET_TYPE_URL);
81+
SECRET_TYPE_URL,
82+
EXTENSION_CONFIG_TYPE_URL);
7783
}
7884

7985
public static final List<ResourceType> RESOURCE_TYPES_IN_ORDER =
80-
ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET);
86+
ImmutableList.of(CLUSTER, ENDPOINT, LISTENER, ROUTE, SECRET, EXTENSION_CONFIG);
8187

8288
public static final Map<String, ResourceType> TYPE_URLS_TO_RESOURCE_TYPE =
8389
new ImmutableMap.Builder<String, ResourceType>()
@@ -86,6 +92,7 @@ public static class V3 {
8692
.put(Resources.V3.LISTENER_TYPE_URL, LISTENER)
8793
.put(Resources.V3.ROUTE_TYPE_URL, ROUTE)
8894
.put(Resources.V3.SECRET_TYPE_URL, SECRET)
95+
.put(Resources.V3.EXTENSION_CONFIG_TYPE_URL, EXTENSION_CONFIG)
8996
.build();
9097

9198
public static final Map<String, Class<? extends Message>> RESOURCE_TYPE_BY_URL =
@@ -95,6 +102,7 @@ public static class V3 {
95102
.put(Resources.V3.LISTENER_TYPE_URL, Listener.class)
96103
.put(Resources.V3.ROUTE_TYPE_URL, RouteConfiguration.class)
97104
.put(Resources.V3.SECRET_TYPE_URL, Secret.class)
105+
.put(Resources.V3.EXTENSION_CONFIG_TYPE_URL, TypedExtensionConfig.class)
98106
.build();
99107

100108
/**
@@ -123,6 +131,10 @@ public static String getResourceName(Message resource) {
123131
return ((Secret) resource).getName();
124132
}
125133

134+
if (resource instanceof TypedExtensionConfig) {
135+
return ((TypedExtensionConfig) resource).getName();
136+
}
137+
126138
return "";
127139
}
128140

‎cache/src/main/java/io/envoyproxy/controlplane/cache/TestResources.java‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import io.envoyproxy.envoy.config.core.v3.GrpcService;
1515
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
1616
import io.envoyproxy.envoy.config.core.v3.SocketAddress.Protocol;
17+
import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig;
1718
import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment;
1819
import io.envoyproxy.envoy.config.endpoint.v3.Endpoint;
1920
import io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint;
@@ -245,5 +246,17 @@ public static Secret createSecret(String secretName) {
245246
.build();
246247
}
247248

249+
/**
250+
* Returns a new test v3 extension config (ECDS), wrapping a no-op HTTP router filter.
251+
*
252+
* @param name name of the new extension config
253+
*/
254+
public static TypedExtensionConfig createExtensionConfig(String name) {
255+
return TypedExtensionConfig.newBuilder()
256+
.setName(name)
257+
.setTypedConfig(Any.pack(Router.newBuilder().build()))
258+
.build();
259+
}
260+
248261
private TestResources() {}
249262
}

‎cache/src/main/java/io/envoyproxy/controlplane/cache/v3/Snapshot.java‎

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import io.envoyproxy.controlplane.cache.SnapshotResources;
1313
import io.envoyproxy.controlplane.cache.VersionedResource;
1414
import io.envoyproxy.envoy.config.cluster.v3.Cluster;
15+
import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig;
1516
import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment;
1617
import io.envoyproxy.envoy.config.listener.v3.Listener;
1718
import io.envoyproxy.envoy.config.route.v3.RouteConfiguration;
@@ -46,6 +47,30 @@ public static Snapshot create(
4647
Iterable<Secret> secrets,
4748
String version) {
4849

50+
return create(clusters, endpoints, listeners, routes, secrets, Collections.emptySet(), version);
51+
}
52+
53+
/**
54+
* Returns a new {@link io.envoyproxy.controlplane.cache.v3.Snapshot} instance that is versioned uniformly across all
55+
* resources, including ECDS extension configs.
56+
*
57+
* @param clusters the cluster resources in this snapshot
58+
* @param endpoints the endpoint resources in this snapshot
59+
* @param listeners the listener resources in this snapshot
60+
* @param routes the route resources in this snapshot
61+
* @param secrets the secret resources in this snapshot
62+
* @param extensionConfigs the ECDS extension config resources in this snapshot
63+
* @param version the version associated with all resources in this snapshot
64+
*/
65+
public static Snapshot create(
66+
Iterable<Cluster> clusters,
67+
Iterable<ClusterLoadAssignment> endpoints,
68+
Iterable<Listener> listeners,
69+
Iterable<RouteConfiguration> routes,
70+
Iterable<Secret> secrets,
71+
Iterable<TypedExtensionConfig> extensionConfigs,
72+
String version) {
73+
4974
return new AutoValue_Snapshot(
5075
SnapshotResources
5176
.create(generateSnapshotResourceIterable(clusters), version),
@@ -56,7 +81,9 @@ public static Snapshot create(
5681
SnapshotResources
5782
.create(generateSnapshotResourceIterable(routes), version),
5883
SnapshotResources
59-
.create(generateSnapshotResourceIterable(secrets), version));
84+
.create(generateSnapshotResourceIterable(secrets), version),
85+
SnapshotResources
86+
.create(generateSnapshotResourceIterable(extensionConfigs), version));
6087
}
6188

6289
/**
@@ -84,6 +111,41 @@ public static Snapshot create(
84111
Iterable<Secret> secrets,
85112
String secretsVersion) {
86113

114+
return create(clusters, clustersVersion, endpoints, endpointsVersion, listeners, listenersVersion,
115+
routes, routesVersion, secrets, secretsVersion, Collections.emptySet(), "");
116+
}
117+
118+
/**
119+
* Returns a new {@link io.envoyproxy.controlplane.cache.v3.Snapshot} instance that has separate versions for each
120+
* resource type, including ECDS extension configs.
121+
*
122+
* @param clusters the cluster resources in this snapshot
123+
* @param clustersVersion the version of the cluster resources
124+
* @param endpoints the endpoint resources in this snapshot
125+
* @param endpointsVersion the version of the endpoint resources
126+
* @param listeners the listener resources in this snapshot
127+
* @param listenersVersion the version of the listener resources
128+
* @param routes the route resources in this snapshot
129+
* @param routesVersion the version of the route resources
130+
* @param secrets the secret resources in this snapshot
131+
* @param secretsVersion the version of the secret resources
132+
* @param extensionConfigs the ECDS extension config resources in this snapshot
133+
* @param extensionConfigsVersion the version of the ECDS extension config resources
134+
*/
135+
public static Snapshot create(
136+
Iterable<Cluster> clusters,
137+
String clustersVersion,
138+
Iterable<ClusterLoadAssignment> endpoints,
139+
String endpointsVersion,
140+
Iterable<Listener> listeners,
141+
String listenersVersion,
142+
Iterable<RouteConfiguration> routes,
143+
String routesVersion,
144+
Iterable<Secret> secrets,
145+
String secretsVersion,
146+
Iterable<TypedExtensionConfig> extensionConfigs,
147+
String extensionConfigsVersion) {
148+
87149
// TODO(snowp): add a builder alternative
88150
return new AutoValue_Snapshot(
89151
SnapshotResources.create(generateSnapshotResourceIterable(clusters),
@@ -95,7 +157,9 @@ public static Snapshot create(
95157
SnapshotResources
96158
.create(generateSnapshotResourceIterable(routes), routesVersion),
97159
SnapshotResources.create(generateSnapshotResourceIterable(secrets),
98-
secretsVersion));
160+
secretsVersion),
161+
SnapshotResources.create(generateSnapshotResourceIterable(extensionConfigs),
162+
extensionConfigsVersion));
99163
}
100164

101165
/**
@@ -133,6 +197,11 @@ public static Snapshot createEmpty(String version) {
133197
*/
134198
public abstract SnapshotResources<Secret> secrets();
135199

200+
/**
201+
* Returns all extension config items in the ECDS payload.
202+
*/
203+
public abstract SnapshotResources<TypedExtensionConfig> extensionConfigs();
204+
136205
/**
137206
* Asserts that all dependent resources are included in the snapshot. All EDS resources are listed by name in CDS
138207
* resources, and all RDS resources are listed by name in LDS resources.
@@ -191,6 +260,8 @@ public Map<String, VersionedResource<?>> resources(String typeUrl) {
191260
return (Map) routes().resources();
192261
case SECRET:
193262
return (Map) secrets().resources();
263+
case EXTENSION_CONFIG:
264+
return (Map) extensionConfigs().resources();
194265
default:
195266
return ImmutableMap.of();
196267
}
@@ -213,6 +284,8 @@ public Map<String, VersionedResource<?>> versionedResources(ResourceType resourc
213284
return (Map) routes().versionedResources();
214285
case SECRET:
215286
return (Map) secrets().versionedResources();
287+
case EXTENSION_CONFIG:
288+
return (Map) extensionConfigs().versionedResources();
216289
default:
217290
return ImmutableMap.of();
218291
}
@@ -268,6 +341,8 @@ public String version(ResourceType resourceType, List<String> resourceNames) {
268341
return routes().version(resourceNames);
269342
case SECRET:
270343
return secrets().version(resourceNames);
344+
case EXTENSION_CONFIG:
345+
return extensionConfigs().version(resourceNames);
271346
default:
272347
return "";
273348
}

‎cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SimpleCacheTest.java‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import io.envoyproxy.controlplane.cache.XdsRequest;
1717
import io.envoyproxy.envoy.config.cluster.v3.Cluster;
1818
import io.envoyproxy.envoy.config.core.v3.Node;
19+
import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig;
1920
import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment;
2021
import io.envoyproxy.envoy.config.listener.v3.Listener;
2122
import io.envoyproxy.envoy.config.route.v3.RouteConfiguration;
@@ -40,6 +41,7 @@ public class SimpleCacheTest {
4041
private static final String LISTENER_NAME = "listener0";
4142
private static final String ROUTE_NAME = "route0";
4243
private static final String SECRET_NAME = "secret0";
44+
private static final String EXTENSION_CONFIG_NAME = "extensionConfig0";
4345

4446
private static final String VERSION1 = UUID.randomUUID().toString();
4547
private static final String VERSION2 = UUID.randomUUID().toString();
@@ -50,6 +52,7 @@ public class SimpleCacheTest {
5052
ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()),
5153
ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()),
5254
ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()),
55+
ImmutableList.of(TypedExtensionConfig.newBuilder().setName(EXTENSION_CONFIG_NAME).build()),
5356
VERSION1);
5457

5558
private static final Snapshot SNAPSHOT2 = Snapshot.create(
@@ -58,6 +61,7 @@ public class SimpleCacheTest {
5861
ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()),
5962
ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()),
6063
ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()),
64+
ImmutableList.of(TypedExtensionConfig.newBuilder().setName(EXTENSION_CONFIG_NAME).build()),
6165
VERSION2);
6266

6367
private static final Snapshot MULTIPLE_RESOURCES_SNAPSHOT2 = Snapshot.create(
@@ -68,6 +72,7 @@ public class SimpleCacheTest {
6872
ImmutableList.of(Listener.newBuilder().setName(LISTENER_NAME).build()),
6973
ImmutableList.of(RouteConfiguration.newBuilder().setName(ROUTE_NAME).build()),
7074
ImmutableList.of(Secret.newBuilder().setName(SECRET_NAME).build()),
75+
ImmutableList.of(TypedExtensionConfig.newBuilder().setName(EXTENSION_CONFIG_NAME).build()),
7176
VERSION2);
7277

7378
private static void assertThatWatchIsOpenWithNoResponses(WatchAndTracker watchAndTracker) {
@@ -297,7 +302,8 @@ public void successfullyWatchAllResourceTypesWithSetBeforeWatchWithRequestVersio
297302
Resources.V3.CLUSTER_TYPE_URL, Resources.V3.ENDPOINT_TYPE_URL,
298303
Resources.V3.ENDPOINT_TYPE_URL, Resources.V3.LISTENER_TYPE_URL,
299304
Resources.V3.LISTENER_TYPE_URL, ROUTE_TYPE_URL, ROUTE_TYPE_URL,
300-
Resources.V3.SECRET_TYPE_URL, Resources.V3.SECRET_TYPE_URL);
305+
Resources.V3.SECRET_TYPE_URL, Resources.V3.SECRET_TYPE_URL,
306+
Resources.V3.EXTENSION_CONFIG_TYPE_URL, Resources.V3.EXTENSION_CONFIG_TYPE_URL);
301307
}
302308

303309
@Test

‎cache/src/test/java/io/envoyproxy/controlplane/cache/v3/SnapshotTest.java‎

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static io.envoyproxy.controlplane.cache.Resources.V3.CLUSTER_TYPE_URL;
44
import static io.envoyproxy.controlplane.cache.Resources.V3.ENDPOINT_TYPE_URL;
5+
import static io.envoyproxy.controlplane.cache.Resources.V3.EXTENSION_CONFIG_TYPE_URL;
56
import static io.envoyproxy.controlplane.cache.Resources.V3.LISTENER_TYPE_URL;
67
import static io.envoyproxy.controlplane.cache.Resources.V3.ROUTE_TYPE_URL;
78
import static io.envoyproxy.envoy.config.core.v3.ApiVersion.V3;
@@ -14,6 +15,7 @@
1415
import io.envoyproxy.controlplane.cache.TestResources;
1516
import io.envoyproxy.controlplane.cache.VersionedResource;
1617
import io.envoyproxy.envoy.config.cluster.v3.Cluster;
18+
import io.envoyproxy.envoy.config.core.v3.TypedExtensionConfig;
1719
import io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment;
1820
import io.envoyproxy.envoy.config.listener.v3.Listener;
1921
import io.envoyproxy.envoy.config.route.v3.RouteConfiguration;
@@ -29,6 +31,7 @@ public class SnapshotTest {
2931
private static final String LISTENER_NAME = "listener0";
3032
private static final String ROUTE_NAME = "route0";
3133
private static final String SECRET_NAME = "secret0";
34+
private static final String EXTENSION_CONFIG_NAME = "extensionConfig0";
3235

3336
private static final int ENDPOINT_PORT = ThreadLocalRandom.current().nextInt(10000, 20000);
3437
private static final int LISTENER_PORT = ThreadLocalRandom.current().nextInt(20000, 30000);
@@ -41,6 +44,8 @@ public class SnapshotTest {
4144
private static final RouteConfiguration ROUTE = TestResources.createRoute(ROUTE_NAME,
4245
CLUSTER_NAME);
4346
private static final Secret SECRET = TestResources.createSecret(SECRET_NAME);
47+
private static final TypedExtensionConfig
48+
EXTENSION_CONFIG = TestResources.createExtensionConfig(EXTENSION_CONFIG_NAME);
4449

4550
@Test
4651
public void createSingleVersionSetsResourcesCorrectly() {
@@ -114,6 +119,58 @@ public void createSeparateVersionsSetsResourcesCorrectly() {
114119
assertThat(snapshot.routes().version()).isEqualTo(routesVersion);
115120
}
116121

122+
@Test
123+
public void createSetsExtensionConfigsCorrectly() {
124+
final String version = UUID.randomUUID().toString();
125+
126+
Snapshot snapshot = Snapshot.create(
127+
ImmutableList.of(CLUSTER),
128+
ImmutableList.of(ENDPOINT),
129+
ImmutableList.of(LISTENER),
130+
ImmutableList.of(ROUTE),
131+
ImmutableList.of(SECRET),
132+
ImmutableList.of(EXTENSION_CONFIG),
133+
version);
134+
135+
assertThat(snapshot.extensionConfigs().resources())
136+
.containsEntry(EXTENSION_CONFIG_NAME, EXTENSION_CONFIG)
137+
.hasSize(1);
138+
assertThat(snapshot.extensionConfigs().version()).isEqualTo(version);
139+
140+
assertThat(snapshot.resources(EXTENSION_CONFIG_TYPE_URL))
141+
.containsEntry(EXTENSION_CONFIG_NAME, VersionedResource.create(EXTENSION_CONFIG))
142+
.hasSize(1);
143+
assertThat(snapshot.version(EXTENSION_CONFIG_TYPE_URL)).isEqualTo(version);
144+
145+
// The legacy create overload leaves the ECDS payload empty.
146+
Snapshot withoutEcds = Snapshot.create(
147+
ImmutableList.of(CLUSTER),
148+
ImmutableList.of(ENDPOINT),
149+
ImmutableList.of(LISTENER),
150+
ImmutableList.of(ROUTE),
151+
ImmutableList.of(SECRET),
152+
version);
153+
assertThat(withoutEcds.extensionConfigs().resources()).isEmpty();
154+
}
155+
156+
@Test
157+
public void createSeparateVersionsSetsExtensionConfigsCorrectly() {
158+
final String extensionConfigsVersion = UUID.randomUUID().toString();
159+
160+
Snapshot snapshot = Snapshot.create(
161+
ImmutableList.of(CLUSTER), UUID.randomUUID().toString(),
162+
ImmutableList.of(ENDPOINT), UUID.randomUUID().toString(),
163+
ImmutableList.of(LISTENER), UUID.randomUUID().toString(),
164+
ImmutableList.of(ROUTE), UUID.randomUUID().toString(),
165+
ImmutableList.of(SECRET), UUID.randomUUID().toString(),
166+
ImmutableList.of(EXTENSION_CONFIG), extensionConfigsVersion);
167+
168+
assertThat(snapshot.extensionConfigs().resources())
169+
.containsEntry(EXTENSION_CONFIG_NAME, EXTENSION_CONFIG)
170+
.hasSize(1);
171+
assertThat(snapshot.extensionConfigs().version()).isEqualTo(extensionConfigsVersion);
172+
}
173+
117174
@Test
118175
@SuppressWarnings("unchecked")
119176
public void resourcesReturnsExpectedResources() {

0 commit comments

Comments
 (0)