mirror of https://github.com/grpc/grpc-java.git
xds: unify client and server handling HttpConnectionManager (#8228)
Enables parsing HttpConnectionManager filter for the server side TCP listener, with the same codepath for handling it on the client side. Major changes include: - Remodeled LdsUpdate with HttpConnectionManager. Now LdsUpdate is an oneof of HttpConnectionManager (for client side) or Listener (for server side). Each of Listener's FiliterChain contains an HttpConnectionManager (required). Refactored code for validating and parsing the TCP Listener (for server side), put it into ClientXdsClient. The common part of validating/parsing HttpConnectionManager is reused/shared for client side. - Included the name of FilterChain in the parsed form. As specified by the API, each FilterChain has a unique name. If the name is not provided by the control plane, a UUID is used. FilterChain names can be used for bookkeeping a set of FilterChain easily (e.g., used as map key). - Added methods isSupportedOnClients() and isSupportedOnServers() to the Filter interface. Parsing the top-level HttpFilter requires knowing if the HttpFilter implementation is supported for the target usage (client-side or server-side). Note, parsing override HttpFilter configs does not need to know whether the config is used for an HttpFilter that is only supported for the client-side or server side. - Added a new kind of Route: Route with non-forwarding action. Updated the XdsNameResolver being able to handle Route with non-forwarding action: if such a Route is matched to an RPC, that RPC is failed. Note, it is possible that XdsNameResolver receives xDS updates with all Routes with non-forwarding action. That is, the service config will not reference any cluster. Such case can be handled by cluster_manager LB policy's LB config parser: the parser returns the error to Channel and the Channel will handle it as error service config.
This commit is contained in:
parent
2258d2e3e9
commit
9a8bc10f51
|
|
@ -18,7 +18,6 @@ package io.grpc.xds;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.grpc.xds.EnvoyServerProtoData.TRANSPORT_SOCKET_NAME_TLS;
|
||||
|
||||
import com.github.udpa.udpa.type.v1.TypedStruct;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
|
@ -43,11 +42,13 @@ import io.envoyproxy.envoy.config.core.v3.HttpProtocolOptions;
|
|||
import io.envoyproxy.envoy.config.core.v3.RoutingPriority;
|
||||
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
|
||||
import io.envoyproxy.envoy.config.core.v3.SocketAddress.PortSpecifierCase;
|
||||
import io.envoyproxy.envoy.config.core.v3.TrafficDirection;
|
||||
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.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager;
|
||||
import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.Rds;
|
||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType;
|
||||
import io.grpc.Context;
|
||||
|
|
@ -60,10 +61,16 @@ import io.grpc.internal.TimeProvider;
|
|||
import io.grpc.xds.Endpoints.DropOverload;
|
||||
import io.grpc.xds.Endpoints.LbEndpoint;
|
||||
import io.grpc.xds.Endpoints.LocalityLbEndpoints;
|
||||
import io.grpc.xds.EnvoyServerProtoData.CidrRange;
|
||||
import io.grpc.xds.EnvoyServerProtoData.ConnectionSourceType;
|
||||
import io.grpc.xds.EnvoyServerProtoData.FilterChain;
|
||||
import io.grpc.xds.EnvoyServerProtoData.FilterChainMatch;
|
||||
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
|
||||
import io.grpc.xds.Filter.ClientInterceptorBuilder;
|
||||
import io.grpc.xds.Filter.ConfigOrError;
|
||||
import io.grpc.xds.Filter.FilterConfig;
|
||||
import io.grpc.xds.Filter.NamedFilterConfig;
|
||||
import io.grpc.xds.Filter.ServerInterceptorBuilder;
|
||||
import io.grpc.xds.LoadStatsManager2.ClusterDropStats;
|
||||
import io.grpc.xds.LoadStatsManager2.ClusterLocalityStats;
|
||||
import io.grpc.xds.VirtualHost.Route;
|
||||
|
|
@ -76,8 +83,10 @@ import io.grpc.xds.XdsLogger.XdsLogLevel;
|
|||
import io.grpc.xds.internal.Matchers.FractionMatcher;
|
||||
import io.grpc.xds.internal.Matchers.HeaderMatcher;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
|
|
@ -85,6 +94,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -97,6 +107,7 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
// Longest time to wait, since the subscription to some resource, for concluding its absence.
|
||||
@VisibleForTesting
|
||||
static final int INITIAL_RESOURCE_FETCH_TIMEOUT_SEC = 15;
|
||||
private static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls";
|
||||
@VisibleForTesting
|
||||
static final long DEFAULT_RING_HASH_LB_POLICY_MIN_RING_SIZE = 1024L;
|
||||
@VisibleForTesting
|
||||
|
|
@ -131,6 +142,7 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
private static final String TYPE_URL_FILTER_CONFIG =
|
||||
"type.googleapis.com/envoy.config.route.v3.FilterConfig";
|
||||
|
||||
private final FilterRegistry filterRegistry = FilterRegistry.getDefaultRegistry();
|
||||
private final Map<String, ResourceSubscriber> ldsResourceSubscribers = new HashMap<>();
|
||||
private final Map<String, ResourceSubscriber> rdsResourceSubscribers = new HashMap<>();
|
||||
private final Map<String, ResourceSubscriber> cdsResourceSubscribers = new HashMap<>();
|
||||
|
|
@ -182,9 +194,11 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
LdsUpdate ldsUpdate;
|
||||
try {
|
||||
if (listener.hasApiListener()) {
|
||||
ldsUpdate = processClientSideListener(listener, enableFaultInjection && isResourceV3);
|
||||
ldsUpdate = processClientSideListener(
|
||||
listener, retainedRdsResources, enableFaultInjection && isResourceV3);
|
||||
} else {
|
||||
ldsUpdate = processServerSideListener(listener);
|
||||
ldsUpdate = processServerSideListener(
|
||||
listener, retainedRdsResources, enableFaultInjection && isResourceV3);
|
||||
}
|
||||
} catch (ResourceInvalidException e) {
|
||||
errors.add(
|
||||
|
|
@ -194,9 +208,6 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
|
||||
// LdsUpdate parsed successfully.
|
||||
parsedResources.put(listenerName, new ParsedResource(ldsUpdate, resource));
|
||||
if (ldsUpdate.rdsName != null) {
|
||||
retainedRdsResources.add(ldsUpdate.rdsName);
|
||||
}
|
||||
}
|
||||
getLogger().log(XdsLogLevel.INFO,
|
||||
"Received LDS Response version {0} nonce {1}. Parsed resources: {2}",
|
||||
|
|
@ -216,7 +227,8 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
}
|
||||
}
|
||||
|
||||
private static LdsUpdate processClientSideListener(Listener listener, boolean parseFilter)
|
||||
private LdsUpdate processClientSideListener(
|
||||
Listener listener, Set<String> rdsResources, boolean parseHttpFilter)
|
||||
throws ResourceInvalidException {
|
||||
// Unpack HttpConnectionManager from the Listener.
|
||||
HttpConnectionManager hcm;
|
||||
|
|
@ -228,86 +240,262 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
throw new ResourceInvalidException(
|
||||
"Could not parse HttpConnectionManager config from ApiListener", e);
|
||||
}
|
||||
return LdsUpdate.forApiListener(parseHttpConnectionManager(
|
||||
hcm, rdsResources, filterRegistry, parseHttpFilter, true /* isForClient */));
|
||||
}
|
||||
|
||||
private LdsUpdate processServerSideListener(
|
||||
Listener proto, Set<String> rdsResources, boolean parseHttpFilter)
|
||||
throws ResourceInvalidException {
|
||||
return LdsUpdate.forTcpListener(parseServerSideListener(
|
||||
proto, rdsResources, tlsContextManager, filterRegistry, parseHttpFilter));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static EnvoyServerProtoData.Listener parseServerSideListener(
|
||||
Listener proto, Set<String> rdsResources, TlsContextManager tlsContextManager,
|
||||
FilterRegistry filterRegistry, boolean parseHttpFilter) throws ResourceInvalidException {
|
||||
if (!proto.getTrafficDirection().equals(TrafficDirection.INBOUND)) {
|
||||
throw new ResourceInvalidException(
|
||||
"Listener " + proto.getName() + " with invalid traffic direction: "
|
||||
+ proto.getTrafficDirection());
|
||||
}
|
||||
if (!proto.getListenerFiltersList().isEmpty()) {
|
||||
throw new ResourceInvalidException(
|
||||
"Listener " + proto.getName() + " cannot have listener_filters");
|
||||
}
|
||||
if (proto.hasUseOriginalDst()) {
|
||||
throw new ResourceInvalidException(
|
||||
"Listener " + proto.getName() + " cannot have use_original_dst set to true");
|
||||
}
|
||||
|
||||
String address = null;
|
||||
if (proto.getAddress().hasSocketAddress()) {
|
||||
SocketAddress socketAddress = proto.getAddress().getSocketAddress();
|
||||
address = socketAddress.getAddress();
|
||||
switch (socketAddress.getPortSpecifierCase()) {
|
||||
case NAMED_PORT:
|
||||
address = address + ":" + socketAddress.getNamedPort();
|
||||
break;
|
||||
case PORT_VALUE:
|
||||
address = address + ":" + socketAddress.getPortValue();
|
||||
break;
|
||||
default:
|
||||
// noop
|
||||
}
|
||||
}
|
||||
|
||||
List<FilterChain> filterChains = new ArrayList<>();
|
||||
for (io.envoyproxy.envoy.config.listener.v3.FilterChain fc : proto.getFilterChainsList()) {
|
||||
filterChains.add(
|
||||
parseFilterChain(fc, rdsResources, tlsContextManager, filterRegistry, parseHttpFilter));
|
||||
}
|
||||
FilterChain defaultFilterChain = null;
|
||||
if (proto.hasDefaultFilterChain()) {
|
||||
defaultFilterChain = parseFilterChain(
|
||||
proto.getDefaultFilterChain(), rdsResources, tlsContextManager, filterRegistry,
|
||||
parseHttpFilter);
|
||||
}
|
||||
|
||||
return new EnvoyServerProtoData.Listener(
|
||||
proto.getName(), address, Collections.unmodifiableList(filterChains), defaultFilterChain);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static FilterChain parseFilterChain(
|
||||
io.envoyproxy.envoy.config.listener.v3.FilterChain proto, Set<String> rdsResources,
|
||||
TlsContextManager tlsContextManager, FilterRegistry filterRegistry, boolean parseHttpFilters)
|
||||
throws ResourceInvalidException {
|
||||
io.grpc.xds.HttpConnectionManager httpConnectionManager = null;
|
||||
HashSet<String> uniqueNames = new HashSet<>();
|
||||
for (io.envoyproxy.envoy.config.listener.v3.Filter filter : proto.getFiltersList()) {
|
||||
if (!uniqueNames.add(filter.getName())) {
|
||||
throw new ResourceInvalidException(
|
||||
"FilterChain " + proto.getName() + " with duplicated filter: " + filter.getName());
|
||||
}
|
||||
if (!filter.hasTypedConfig()) {
|
||||
throw new ResourceInvalidException(
|
||||
"FilterChain " + proto.getName() + " contains filter " + filter.getName()
|
||||
+ " without typed_config");
|
||||
}
|
||||
Any any = filter.getTypedConfig();
|
||||
// HttpConnectionManager is the only supported network filter at the moment.
|
||||
if (!any.getTypeUrl().equals(TYPE_URL_HTTP_CONNECTION_MANAGER)) {
|
||||
throw new ResourceInvalidException(
|
||||
"FilterChain " + proto.getName() + " contains filter " + filter.getName()
|
||||
+ " with unsupported typed_config type " + any.getTypeUrl());
|
||||
}
|
||||
if (httpConnectionManager == null) {
|
||||
HttpConnectionManager hcmProto;
|
||||
try {
|
||||
hcmProto = any.unpack(HttpConnectionManager.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new ResourceInvalidException("FilterChain " + proto.getName() + " with filter "
|
||||
+ filter.getName() + " failed to unpack message", e);
|
||||
}
|
||||
httpConnectionManager = parseHttpConnectionManager(
|
||||
hcmProto, rdsResources, filterRegistry, parseHttpFilters, false /* isForClient */);
|
||||
}
|
||||
}
|
||||
if (httpConnectionManager == null) {
|
||||
throw new ResourceInvalidException("FilterChain " + proto.getName()
|
||||
+ " missing required HttpConnectionManager filter");
|
||||
}
|
||||
|
||||
EnvoyServerProtoData.DownstreamTlsContext downstreamTlsContext = null;
|
||||
if (TRANSPORT_SOCKET_NAME_TLS.equals(proto.getTransportSocket().getName())) {
|
||||
DownstreamTlsContext downstreamTlsContextProto;
|
||||
try {
|
||||
downstreamTlsContextProto =
|
||||
proto.getTransportSocket().getTypedConfig().unpack(DownstreamTlsContext.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
throw new ResourceInvalidException("FilterChain " + proto.getName()
|
||||
+ " failed to unpack message", e);
|
||||
}
|
||||
downstreamTlsContext =
|
||||
EnvoyServerProtoData.DownstreamTlsContext.fromEnvoyProtoDownstreamTlsContext(
|
||||
downstreamTlsContextProto);
|
||||
}
|
||||
|
||||
String name = proto.getName();
|
||||
if (name.isEmpty()) {
|
||||
name = UUID.randomUUID().toString();
|
||||
}
|
||||
return new FilterChain(
|
||||
name,
|
||||
parseFilterChainMatch(proto.getFilterChainMatch()),
|
||||
httpConnectionManager,
|
||||
downstreamTlsContext,
|
||||
tlsContextManager
|
||||
);
|
||||
}
|
||||
|
||||
private static FilterChainMatch parseFilterChainMatch(
|
||||
io.envoyproxy.envoy.config.listener.v3.FilterChainMatch proto)
|
||||
throws ResourceInvalidException {
|
||||
List<CidrRange> prefixRanges = new ArrayList<>();
|
||||
List<CidrRange> sourcePrefixRanges = new ArrayList<>();
|
||||
try {
|
||||
for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getPrefixRangesList()) {
|
||||
prefixRanges.add(new CidrRange(range.getAddressPrefix(), range.getPrefixLen().getValue()));
|
||||
}
|
||||
for (io.envoyproxy.envoy.config.core.v3.CidrRange range
|
||||
: proto.getSourcePrefixRangesList()) {
|
||||
sourcePrefixRanges.add(
|
||||
new CidrRange(range.getAddressPrefix(), range.getPrefixLen().getValue()));
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
throw new ResourceInvalidException("Failed to create CidrRange", e);
|
||||
}
|
||||
ConnectionSourceType sourceType;
|
||||
switch (proto.getSourceType()) {
|
||||
case ANY:
|
||||
sourceType = ConnectionSourceType.ANY;
|
||||
break;
|
||||
case EXTERNAL:
|
||||
sourceType = ConnectionSourceType.EXTERNAL;
|
||||
break;
|
||||
case SAME_IP_OR_LOOPBACK:
|
||||
sourceType = ConnectionSourceType.SAME_IP_OR_LOOPBACK;
|
||||
break;
|
||||
default:
|
||||
throw new ResourceInvalidException("Unknown source-type: " + proto.getSourceType());
|
||||
}
|
||||
return new FilterChainMatch(
|
||||
proto.getDestinationPort().getValue(),
|
||||
prefixRanges,
|
||||
proto.getApplicationProtocolsList(),
|
||||
sourcePrefixRanges,
|
||||
sourceType,
|
||||
proto.getSourcePortsList(),
|
||||
proto.getServerNamesList(),
|
||||
proto.getTransportProtocol());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager(
|
||||
HttpConnectionManager proto, Set<String> rdsResources, FilterRegistry filterRegistry,
|
||||
boolean parseHttpFilter, boolean isForClient) throws ResourceInvalidException {
|
||||
if (proto.getXffNumTrustedHops() != 0) {
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager with xff_num_trusted_hops unsupported");
|
||||
}
|
||||
// Obtain max_stream_duration from Http Protocol Options.
|
||||
long maxStreamDuration = 0;
|
||||
if (hcm.hasCommonHttpProtocolOptions()) {
|
||||
HttpProtocolOptions options = hcm.getCommonHttpProtocolOptions();
|
||||
if (proto.hasCommonHttpProtocolOptions()) {
|
||||
HttpProtocolOptions options = proto.getCommonHttpProtocolOptions();
|
||||
if (options.hasMaxStreamDuration()) {
|
||||
maxStreamDuration = Durations.toNanos(options.getMaxStreamDuration());
|
||||
}
|
||||
}
|
||||
|
||||
// Parse filters.
|
||||
List<NamedFilterConfig> filterChain = null;
|
||||
if (parseFilter) {
|
||||
filterChain = new ArrayList<>();
|
||||
List<io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter>
|
||||
httpFilters = hcm.getHttpFiltersList();
|
||||
// Parse http filters.
|
||||
List<NamedFilterConfig> filterConfigs = null;
|
||||
if (parseHttpFilter) {
|
||||
filterConfigs = new ArrayList<>();
|
||||
Set<String> names = new HashSet<>();
|
||||
for (io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
|
||||
httpFilter : httpFilters) {
|
||||
httpFilter : proto.getHttpFiltersList()) {
|
||||
String filterName = httpFilter.getName();
|
||||
StructOrError<FilterConfig> filterConfig = parseHttpFilter(httpFilter);
|
||||
if (!names.add(filterName)) {
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager contains duplicate HttpFilter: " + filterName);
|
||||
}
|
||||
StructOrError<FilterConfig> filterConfig =
|
||||
parseHttpFilter(httpFilter, filterRegistry, isForClient);
|
||||
if (filterConfig == null) {
|
||||
continue;
|
||||
}
|
||||
if (filterConfig.getErrorDetail() != null) {
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager contains invalid HttpFault filter: "
|
||||
"HttpConnectionManager contains invalid HttpFilter: "
|
||||
+ filterConfig.getErrorDetail());
|
||||
}
|
||||
filterChain.add(new NamedFilterConfig(filterName, filterConfig.struct));
|
||||
filterConfigs.add(new NamedFilterConfig(filterName, filterConfig.struct));
|
||||
}
|
||||
}
|
||||
|
||||
// Parse RDS info.
|
||||
if (hcm.hasRouteConfig()) {
|
||||
// Found inlined route_config. Parse it to find the cluster_name.
|
||||
// Parse inlined RouteConfiguration or RDS.
|
||||
if (proto.hasRouteConfig()) {
|
||||
List<VirtualHost> virtualHosts = new ArrayList<>();
|
||||
for (io.envoyproxy.envoy.config.route.v3.VirtualHost virtualHostProto
|
||||
: hcm.getRouteConfig().getVirtualHostsList()) {
|
||||
StructOrError<VirtualHost> virtualHost = parseVirtualHost(virtualHostProto, parseFilter);
|
||||
: proto.getRouteConfig().getVirtualHostsList()) {
|
||||
StructOrError<VirtualHost> virtualHost =
|
||||
parseVirtualHost(virtualHostProto, filterRegistry, parseHttpFilter);
|
||||
if (virtualHost.getErrorDetail() != null) {
|
||||
throw new ResourceInvalidException("HttpConnectionManager contains invalid virtual host: "
|
||||
+ virtualHost.getErrorDetail());
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager contains invalid virtual host: "
|
||||
+ virtualHost.getErrorDetail());
|
||||
}
|
||||
virtualHosts.add(virtualHost.getStruct());
|
||||
}
|
||||
return new LdsUpdate(maxStreamDuration, virtualHosts, filterChain);
|
||||
return io.grpc.xds.HttpConnectionManager.forVirtualHosts(
|
||||
maxStreamDuration, virtualHosts, filterConfigs);
|
||||
}
|
||||
|
||||
if (hcm.hasRds()) {
|
||||
// Found RDS.
|
||||
Rds rds = hcm.getRds();
|
||||
if (proto.hasRds()) {
|
||||
Rds rds = proto.getRds();
|
||||
if (!rds.hasConfigSource()) {
|
||||
throw new ResourceInvalidException("HttpConnectionManager missing config_source for RDS.");
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager contains invalid RDS: missing config_source");
|
||||
}
|
||||
if (!rds.getConfigSource().hasAds()) {
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager ConfigSource for RDS does not specify ADS.");
|
||||
"HttpConnectionManager contains invalid RDS: must specify ADS");
|
||||
}
|
||||
return new LdsUpdate(maxStreamDuration, rds.getRouteConfigName(), filterChain);
|
||||
// Collect the RDS resource referenced by this HttpConnectionManager.
|
||||
rdsResources.add(rds.getRouteConfigName());
|
||||
return io.grpc.xds.HttpConnectionManager.forRdsName(
|
||||
maxStreamDuration, rds.getRouteConfigName(), filterConfigs);
|
||||
}
|
||||
|
||||
throw new ResourceInvalidException(
|
||||
"HttpConnectionManager neither has inlined route_config nor RDS.");
|
||||
}
|
||||
|
||||
private LdsUpdate processServerSideListener(Listener listener)
|
||||
throws ResourceInvalidException {
|
||||
StructOrError<EnvoyServerProtoData.Listener> convertedListener =
|
||||
parseServerSideListener(listener, tlsContextManager);
|
||||
if (convertedListener.getErrorDetail() != null) {
|
||||
throw new ResourceInvalidException(convertedListener.getErrorDetail());
|
||||
}
|
||||
return new LdsUpdate(convertedListener.getStruct());
|
||||
"HttpConnectionManager neither has inlined route_config nor RDS");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable // Returns null if the filter is optional but not supported.
|
||||
static StructOrError<FilterConfig> parseHttpFilter(
|
||||
io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
|
||||
httpFilter) {
|
||||
httpFilter, FilterRegistry filterRegistry, boolean isForClient) {
|
||||
String filterName = httpFilter.getName();
|
||||
boolean isOptional = httpFilter.getIsOptional();
|
||||
if (!httpFilter.hasTypedConfig()) {
|
||||
|
|
@ -318,36 +506,12 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
"HttpFilter [" + filterName + "] is not optional and has no typed config");
|
||||
}
|
||||
}
|
||||
return parseRawFilterConfig(filterName, httpFilter.getTypedConfig(), isOptional, false);
|
||||
}
|
||||
|
||||
@Nullable // Returns null if the filter should be ignored.
|
||||
private static StructOrError<FilterConfig> parseRawFilterConfig(
|
||||
String filterName, Any anyConfig, Boolean isOptional, boolean isOverrideConfig) {
|
||||
checkArgument(
|
||||
isOptional != null || isOverrideConfig, "isOptional can't be null for top-level config");
|
||||
String typeUrl = anyConfig.getTypeUrl();
|
||||
if (isOverrideConfig) {
|
||||
isOptional = false;
|
||||
if (typeUrl.equals(TYPE_URL_FILTER_CONFIG)) {
|
||||
io.envoyproxy.envoy.config.route.v3.FilterConfig filterConfig;
|
||||
try {
|
||||
filterConfig =
|
||||
anyConfig.unpack(io.envoyproxy.envoy.config.route.v3.FilterConfig.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return StructOrError.fromError(
|
||||
"HttpFilter [" + filterName + "] contains invalid proto: " + e);
|
||||
}
|
||||
isOptional = filterConfig.getIsOptional();
|
||||
anyConfig = filterConfig.getConfig();
|
||||
typeUrl = anyConfig.getTypeUrl();
|
||||
}
|
||||
}
|
||||
Message rawConfig = anyConfig;
|
||||
if (anyConfig.getTypeUrl().equals(TYPE_URL_TYPED_STRUCT)) {
|
||||
Message rawConfig = httpFilter.getTypedConfig();
|
||||
String typeUrl = httpFilter.getTypedConfig().getTypeUrl();
|
||||
if (typeUrl.equals(TYPE_URL_TYPED_STRUCT)) {
|
||||
TypedStruct typedStruct;
|
||||
try {
|
||||
typedStruct = anyConfig.unpack(TypedStruct.class);
|
||||
typedStruct = httpFilter.getTypedConfig().unpack(TypedStruct.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return StructOrError.fromError(
|
||||
"HttpFilter [" + filterName + "] contains invalid proto: " + e);
|
||||
|
|
@ -355,18 +519,18 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
typeUrl = typedStruct.getTypeUrl();
|
||||
rawConfig = typedStruct.getValue();
|
||||
}
|
||||
Filter filter = FilterRegistry.getDefaultRegistry().get(typeUrl);
|
||||
if (filter == null) {
|
||||
Filter filter = filterRegistry.get(typeUrl);
|
||||
if ((isForClient && !(filter instanceof ClientInterceptorBuilder))
|
||||
|| (!isForClient && !(filter instanceof ServerInterceptorBuilder))) {
|
||||
if (isOptional) {
|
||||
return null;
|
||||
} else {
|
||||
return StructOrError.fromError(
|
||||
"HttpFilter [" + filterName + "] is not optional and has an unsupported config type: "
|
||||
+ typeUrl);
|
||||
"HttpFilter [" + filterName + "](" + typeUrl + ") is required but unsupported for "
|
||||
+ (isForClient ? "client" : "server"));
|
||||
}
|
||||
}
|
||||
ConfigOrError<? extends FilterConfig> filterConfig = isOverrideConfig
|
||||
? filter.parseFilterConfigOverride(rawConfig) : filter.parseFilterConfig(rawConfig);
|
||||
ConfigOrError<? extends FilterConfig> filterConfig = filter.parseFilterConfig(rawConfig);
|
||||
if (filterConfig.errorDetail != null) {
|
||||
return StructOrError.fromError(
|
||||
"Invalid filter config for HttpFilter [" + filterName + "]: " + filterConfig.errorDetail);
|
||||
|
|
@ -374,25 +538,13 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
return StructOrError.fromStruct(filterConfig.config);
|
||||
}
|
||||
|
||||
@VisibleForTesting static StructOrError<EnvoyServerProtoData.Listener> parseServerSideListener(
|
||||
Listener listener, TlsContextManager tlsContextManager) {
|
||||
try {
|
||||
return StructOrError.fromStruct(
|
||||
EnvoyServerProtoData.Listener.fromEnvoyProtoListener(listener, tlsContextManager));
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return StructOrError.fromError(
|
||||
"Failed to unpack Listener " + listener.getName() + ":" + e.getMessage());
|
||||
} catch (IllegalArgumentException e) {
|
||||
return StructOrError.fromError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static StructOrError<VirtualHost> parseVirtualHost(
|
||||
io.envoyproxy.envoy.config.route.v3.VirtualHost proto, boolean parseFilter) {
|
||||
io.envoyproxy.envoy.config.route.v3.VirtualHost proto, FilterRegistry filterRegistry,
|
||||
boolean parseHttpFilter) {
|
||||
String name = proto.getName();
|
||||
List<Route> routes = new ArrayList<>(proto.getRoutesCount());
|
||||
for (io.envoyproxy.envoy.config.route.v3.Route routeProto : proto.getRoutesList()) {
|
||||
StructOrError<Route> route = parseRoute(routeProto, parseFilter);
|
||||
StructOrError<Route> route = parseRoute(routeProto, filterRegistry, parseHttpFilter);
|
||||
if (route == null) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -402,12 +554,12 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
}
|
||||
routes.add(route.getStruct());
|
||||
}
|
||||
if (!parseFilter) {
|
||||
if (!parseHttpFilter) {
|
||||
return StructOrError.fromStruct(VirtualHost.create(
|
||||
name, proto.getDomainsList(), routes, new HashMap<String, FilterConfig>()));
|
||||
}
|
||||
StructOrError<Map<String, FilterConfig>> overrideConfigs =
|
||||
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap());
|
||||
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry);
|
||||
if (overrideConfigs.errorDetail != null) {
|
||||
return StructOrError.fromError(
|
||||
"VirtualHost [" + proto.getName() + "] contains invalid HttpFilter config: "
|
||||
|
|
@ -419,18 +571,52 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
|
||||
@VisibleForTesting
|
||||
static StructOrError<Map<String, FilterConfig>> parseOverrideFilterConfigs(
|
||||
Map<String, Any> rawFilterConfigMap) {
|
||||
Map<String, Any> rawFilterConfigMap, FilterRegistry filterRegistry) {
|
||||
Map<String, FilterConfig> overrideConfigs = new HashMap<>();
|
||||
for (String name : rawFilterConfigMap.keySet()) {
|
||||
Any anyConfig = rawFilterConfigMap.get(name);
|
||||
StructOrError<FilterConfig> filterConfig = parseRawFilterConfig(name, anyConfig, null, true);
|
||||
if (filterConfig == null) {
|
||||
continue;
|
||||
String typeUrl = anyConfig.getTypeUrl();
|
||||
boolean isOptional = false;
|
||||
if (typeUrl.equals(TYPE_URL_FILTER_CONFIG)) {
|
||||
io.envoyproxy.envoy.config.route.v3.FilterConfig filterConfig;
|
||||
try {
|
||||
filterConfig =
|
||||
anyConfig.unpack(io.envoyproxy.envoy.config.route.v3.FilterConfig.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return StructOrError.fromError(
|
||||
"FilterConfig [" + name + "] contains invalid proto: " + e);
|
||||
}
|
||||
isOptional = filterConfig.getIsOptional();
|
||||
anyConfig = filterConfig.getConfig();
|
||||
typeUrl = anyConfig.getTypeUrl();
|
||||
}
|
||||
Message rawConfig = anyConfig;
|
||||
if (typeUrl.equals(TYPE_URL_TYPED_STRUCT)) {
|
||||
TypedStruct typedStruct;
|
||||
try {
|
||||
typedStruct = anyConfig.unpack(TypedStruct.class);
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
return StructOrError.fromError(
|
||||
"FilterConfig [" + name + "] contains invalid proto: " + e);
|
||||
}
|
||||
typeUrl = typedStruct.getTypeUrl();
|
||||
rawConfig = typedStruct.getValue();
|
||||
}
|
||||
Filter filter = filterRegistry.get(typeUrl);
|
||||
if (filter == null) {
|
||||
if (isOptional) {
|
||||
continue;
|
||||
}
|
||||
return StructOrError.fromError(
|
||||
"HttpFilter [" + name + "](" + typeUrl + ") is required but unsupported");
|
||||
}
|
||||
ConfigOrError<? extends FilterConfig> filterConfig =
|
||||
filter.parseFilterConfigOverride(rawConfig);
|
||||
if (filterConfig.errorDetail != null) {
|
||||
return StructOrError.fromError(filterConfig.errorDetail);
|
||||
return StructOrError.fromError(
|
||||
"Invalid filter config for HttpFilter [" + name + "]: " + filterConfig.errorDetail);
|
||||
}
|
||||
overrideConfigs.put(name, filterConfig.struct);
|
||||
overrideConfigs.put(name, filterConfig.config);
|
||||
}
|
||||
return StructOrError.fromStruct(overrideConfigs);
|
||||
}
|
||||
|
|
@ -438,51 +624,55 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
@VisibleForTesting
|
||||
@Nullable
|
||||
static StructOrError<Route> parseRoute(
|
||||
io.envoyproxy.envoy.config.route.v3.Route proto, boolean parseFilter) {
|
||||
io.envoyproxy.envoy.config.route.v3.Route proto, FilterRegistry filterRegistry,
|
||||
boolean parseHttpFilter) {
|
||||
StructOrError<RouteMatch> routeMatch = parseRouteMatch(proto.getMatch());
|
||||
if (routeMatch == null) {
|
||||
return null;
|
||||
}
|
||||
if (routeMatch.getErrorDetail() != null) {
|
||||
return StructOrError.fromError(
|
||||
"Invalid route [" + proto.getName() + "]: " + routeMatch.getErrorDetail());
|
||||
"Route [" + proto.getName() + "] contains invalid RouteMatch: "
|
||||
+ routeMatch.getErrorDetail());
|
||||
}
|
||||
|
||||
Map<String, FilterConfig> overrideConfigs = Collections.emptyMap();
|
||||
if (parseHttpFilter) {
|
||||
StructOrError<Map<String, FilterConfig>> overrideConfigsOrError =
|
||||
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry);
|
||||
if (overrideConfigsOrError.errorDetail != null) {
|
||||
return StructOrError.fromError(
|
||||
"Route [" + proto.getName() + "] contains invalid HttpFilter config: "
|
||||
+ overrideConfigsOrError.errorDetail);
|
||||
}
|
||||
overrideConfigs = overrideConfigsOrError.struct;
|
||||
}
|
||||
|
||||
StructOrError<RouteAction> routeAction;
|
||||
switch (proto.getActionCase()) {
|
||||
case ROUTE:
|
||||
routeAction = parseRouteAction(proto.getRoute(), parseFilter);
|
||||
break;
|
||||
StructOrError<RouteAction> routeAction =
|
||||
parseRouteAction(proto.getRoute(), filterRegistry, parseHttpFilter);
|
||||
if (routeAction == null) {
|
||||
return null;
|
||||
}
|
||||
if (routeAction.errorDetail != null) {
|
||||
return StructOrError.fromError(
|
||||
"Route [" + proto.getName() + "] contains invalid RouteAction: "
|
||||
+ routeAction.getErrorDetail());
|
||||
}
|
||||
return StructOrError.fromStruct(
|
||||
Route.forAction(routeMatch.struct, routeAction.struct, overrideConfigs));
|
||||
case NON_FORWARDING_ACTION:
|
||||
return StructOrError.fromStruct(
|
||||
Route.forNonForwardingAction(routeMatch.struct, overrideConfigs));
|
||||
case REDIRECT:
|
||||
return StructOrError.fromError("Unsupported action type: redirect");
|
||||
case DIRECT_RESPONSE:
|
||||
return StructOrError.fromError("Unsupported action type: direct_response");
|
||||
case FILTER_ACTION:
|
||||
return StructOrError.fromError("Unsupported action type: filter_action");
|
||||
case ACTION_NOT_SET:
|
||||
default:
|
||||
return StructOrError.fromError("Unknown action type: " + proto.getActionCase());
|
||||
return StructOrError.fromError(
|
||||
"Route [" + proto.getName() + "] with unknown action type: " + proto.getActionCase());
|
||||
}
|
||||
if (routeAction == null) {
|
||||
return null;
|
||||
}
|
||||
if (routeAction.getErrorDetail() != null) {
|
||||
return StructOrError.fromError(
|
||||
"Invalid route [" + proto.getName() + "]: " + routeAction.getErrorDetail());
|
||||
}
|
||||
if (!parseFilter) {
|
||||
return StructOrError.fromStruct(Route.create(
|
||||
routeMatch.getStruct(), routeAction.getStruct(), new HashMap<String, FilterConfig>()));
|
||||
}
|
||||
StructOrError<Map<String, FilterConfig>> overrideConfigs =
|
||||
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap());
|
||||
if (overrideConfigs.errorDetail != null) {
|
||||
return StructOrError.fromError(
|
||||
"Route [" + proto.getName() + "] contains invalid HttpFilter config: "
|
||||
+ overrideConfigs.errorDetail);
|
||||
}
|
||||
return StructOrError.fromStruct(Route.create(
|
||||
routeMatch.getStruct(), routeAction.getStruct(), overrideConfigs.struct));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
@ -605,10 +795,16 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the RouteAction config. The returned result may contain a (parsed form)
|
||||
* {@link RouteAction} or an error message. Returns {@code null} if the RouteAction
|
||||
* should be ignored.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
static StructOrError<RouteAction> parseRouteAction(
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto, boolean parseFilter) {
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction proto, FilterRegistry filterRegistry,
|
||||
boolean parseHttpFilter) {
|
||||
Long timeoutNano = null;
|
||||
if (proto.hasMaxStreamDuration()) {
|
||||
io.envoyproxy.envoy.config.route.v3.RouteAction.MaxStreamDuration maxStreamDuration
|
||||
|
|
@ -667,7 +863,7 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
for (io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight clusterWeight
|
||||
: clusterWeights) {
|
||||
StructOrError<ClusterWeight> clusterWeightOrError =
|
||||
parseClusterWeight(clusterWeight, parseFilter);
|
||||
parseClusterWeight(clusterWeight, filterRegistry, parseHttpFilter);
|
||||
if (clusterWeightOrError.getErrorDetail() != null) {
|
||||
return StructOrError.fromError("RouteAction contains invalid ClusterWeight: "
|
||||
+ clusterWeightOrError.getErrorDetail());
|
||||
|
|
@ -687,13 +883,13 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
@VisibleForTesting
|
||||
static StructOrError<ClusterWeight> parseClusterWeight(
|
||||
io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight proto,
|
||||
boolean parseFilter) {
|
||||
if (!parseFilter) {
|
||||
FilterRegistry filterRegistry, boolean parseHttpFilter) {
|
||||
if (!parseHttpFilter) {
|
||||
return StructOrError.fromStruct(ClusterWeight.create(
|
||||
proto.getName(), proto.getWeight().getValue(), new HashMap<String, FilterConfig>()));
|
||||
}
|
||||
StructOrError<Map<String, FilterConfig>> overrideConfigs =
|
||||
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap());
|
||||
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry);
|
||||
if (overrideConfigs.errorDetail != null) {
|
||||
return StructOrError.fromError(
|
||||
"ClusterWeight [" + proto.getName() + "] contains invalid HttpFilter config: "
|
||||
|
|
@ -728,7 +924,8 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
RdsUpdate rdsUpdate;
|
||||
boolean isResourceV3 = resource.getTypeUrl().equals(ResourceType.RDS.typeUrl());
|
||||
try {
|
||||
rdsUpdate = processRouteConfiguration(routeConfig, enableFaultInjection && isResourceV3);
|
||||
rdsUpdate = processRouteConfiguration(
|
||||
routeConfig, filterRegistry, enableFaultInjection && isResourceV3);
|
||||
} catch (ResourceInvalidException e) {
|
||||
errors.add(
|
||||
"RDS response RouteConfiguration '" + routeConfigName + "' validation error: " + e
|
||||
|
|
@ -750,11 +947,13 @@ final class ClientXdsClient extends AbstractXdsClient {
|
|||
}
|
||||
|
||||
private static RdsUpdate processRouteConfiguration(
|
||||
RouteConfiguration routeConfig, boolean parseFilter) throws ResourceInvalidException {
|
||||
RouteConfiguration routeConfig, FilterRegistry filterRegistry, boolean parseHttpFilter)
|
||||
throws ResourceInvalidException {
|
||||
List<VirtualHost> virtualHosts = new ArrayList<>(routeConfig.getVirtualHostsCount());
|
||||
for (io.envoyproxy.envoy.config.route.v3.VirtualHost virtualHostProto
|
||||
: routeConfig.getVirtualHostsList()) {
|
||||
StructOrError<VirtualHost> virtualHost = parseVirtualHost(virtualHostProto, parseFilter);
|
||||
StructOrError<VirtualHost> virtualHost =
|
||||
parseVirtualHost(virtualHostProto, filterRegistry, parseHttpFilter);
|
||||
if (virtualHost.getErrorDetail() != null) {
|
||||
throw new ResourceInvalidException(
|
||||
"RouteConfiguration contains invalid virtual host: " + virtualHost.getErrorDetail());
|
||||
|
|
|
|||
|
|
@ -16,24 +16,16 @@
|
|||
|
||||
package io.grpc.xds;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import io.envoyproxy.envoy.config.core.v3.Address;
|
||||
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
|
||||
import io.envoyproxy.envoy.config.core.v3.TrafficDirection;
|
||||
import io.envoyproxy.envoy.config.listener.v3.Filter;
|
||||
import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager;
|
||||
import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter;
|
||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
||||
import io.grpc.Internal;
|
||||
import io.grpc.xds.internal.sds.SslContextProviderSupplier;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -45,8 +37,6 @@ import javax.annotation.Nullable;
|
|||
@Internal
|
||||
public final class EnvoyServerProtoData {
|
||||
|
||||
static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls";
|
||||
|
||||
// Prevent instantiation.
|
||||
private EnvoyServerProtoData() {
|
||||
}
|
||||
|
|
@ -156,21 +146,11 @@ public final class EnvoyServerProtoData {
|
|||
private final InetAddress addressPrefix;
|
||||
private final int prefixLen;
|
||||
|
||||
@VisibleForTesting
|
||||
CidrRange(String addressPrefix, int prefixLen) throws InvalidProtocolBufferException {
|
||||
try {
|
||||
this.addressPrefix = InetAddress.getByName(addressPrefix);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new InvalidProtocolBufferException(e.getMessage());
|
||||
}
|
||||
CidrRange(String addressPrefix, int prefixLen) throws UnknownHostException {
|
||||
this.addressPrefix = InetAddress.getByName(addressPrefix);
|
||||
this.prefixLen = prefixLen;
|
||||
}
|
||||
|
||||
static CidrRange fromEnvoyProtoCidrRange(
|
||||
io.envoyproxy.envoy.config.core.v3.CidrRange proto) throws InvalidProtocolBufferException {
|
||||
return new CidrRange(proto.getAddressPrefix(), proto.getPrefixLen().getValue());
|
||||
}
|
||||
|
||||
public InetAddress getAddressPrefix() {
|
||||
return addressPrefix;
|
||||
}
|
||||
|
|
@ -251,50 +231,6 @@ public final class EnvoyServerProtoData {
|
|||
this.transportProtocol = transportProtocol;
|
||||
}
|
||||
|
||||
static FilterChainMatch fromEnvoyProtoFilterChainMatch(
|
||||
io.envoyproxy.envoy.config.listener.v3.FilterChainMatch proto)
|
||||
throws InvalidProtocolBufferException {
|
||||
List<CidrRange> prefixRanges = new ArrayList<>();
|
||||
for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getPrefixRangesList()) {
|
||||
prefixRanges.add(CidrRange.fromEnvoyProtoCidrRange(range));
|
||||
}
|
||||
List<CidrRange> sourcePrefixRanges = new ArrayList<>();
|
||||
for (io.envoyproxy.envoy.config.core.v3.CidrRange range : proto.getSourcePrefixRangesList()) {
|
||||
sourcePrefixRanges.add(CidrRange.fromEnvoyProtoCidrRange(range));
|
||||
}
|
||||
List<String> applicationProtocols = new ArrayList<>();
|
||||
for (String appProtocol : proto.getApplicationProtocolsList()) {
|
||||
applicationProtocols.add(appProtocol);
|
||||
}
|
||||
ConnectionSourceType sourceType = null;
|
||||
switch (proto.getSourceType()) {
|
||||
case ANY:
|
||||
sourceType = ConnectionSourceType.ANY;
|
||||
break;
|
||||
case EXTERNAL:
|
||||
sourceType = ConnectionSourceType.EXTERNAL;
|
||||
break;
|
||||
case SAME_IP_OR_LOOPBACK:
|
||||
sourceType = ConnectionSourceType.SAME_IP_OR_LOOPBACK;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidProtocolBufferException("Unknown source-type:" + proto.getSourceType());
|
||||
}
|
||||
List<String> serverNames = new ArrayList<>();
|
||||
for (String serverName : proto.getServerNamesList()) {
|
||||
serverNames.add(serverName);
|
||||
}
|
||||
return new FilterChainMatch(
|
||||
proto.getDestinationPort().getValue(),
|
||||
prefixRanges,
|
||||
applicationProtocols,
|
||||
sourcePrefixRanges,
|
||||
sourceType,
|
||||
proto.getSourcePortsList(),
|
||||
serverNames,
|
||||
proto.getTransportProtocol());
|
||||
}
|
||||
|
||||
public int getDestinationPort() {
|
||||
return destinationPort;
|
||||
}
|
||||
|
|
@ -378,116 +314,43 @@ public final class EnvoyServerProtoData {
|
|||
* Corresponds to Envoy proto message {@link io.envoyproxy.envoy.api.v2.listener.FilterChain}.
|
||||
*/
|
||||
static final class FilterChain {
|
||||
// Unique name for the FilterChain.
|
||||
private final String name;
|
||||
// TODO(sanjaypujare): flatten structure by moving FilterChainMatch class members here.
|
||||
private final FilterChainMatch filterChainMatch;
|
||||
private final HttpConnectionManager httpConnectionManager;
|
||||
@Nullable
|
||||
private final SslContextProviderSupplier sslContextProviderSupplier;
|
||||
|
||||
@VisibleForTesting
|
||||
FilterChain(
|
||||
FilterChainMatch filterChainMatch, @Nullable DownstreamTlsContext downstreamTlsContext,
|
||||
String name,
|
||||
FilterChainMatch filterChainMatch,
|
||||
HttpConnectionManager httpConnectionManager,
|
||||
@Nullable DownstreamTlsContext downstreamTlsContext,
|
||||
TlsContextManager tlsContextManager) {
|
||||
SslContextProviderSupplier sslContextProviderSupplier1 = downstreamTlsContext == null ? null
|
||||
: new SslContextProviderSupplier(downstreamTlsContext, tlsContextManager);
|
||||
this.name = checkNotNull(name, "name");
|
||||
// TODO(chengyuanzhang): enforce non-null, change tests to use a default/empty
|
||||
// FilterChainMatch instead of null, as that's how the proto is converted.
|
||||
this.filterChainMatch = filterChainMatch;
|
||||
this.sslContextProviderSupplier = sslContextProviderSupplier1;
|
||||
this.httpConnectionManager = checkNotNull(httpConnectionManager, "httpConnectionManager");
|
||||
}
|
||||
|
||||
static FilterChain fromEnvoyProtoFilterChain(
|
||||
io.envoyproxy.envoy.config.listener.v3.FilterChain proto,
|
||||
TlsContextManager tlsContextManager, boolean isDefaultFilterChain)
|
||||
throws InvalidProtocolBufferException {
|
||||
if (!isDefaultFilterChain && proto.getFiltersList().isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"filerChain " + proto.getName() + " has to have envoy.http_connection_manager");
|
||||
}
|
||||
HashSet<String> uniqueNames = new HashSet<>();
|
||||
for (Filter filter : proto.getFiltersList()) {
|
||||
if (!uniqueNames.add(filter.getName())) {
|
||||
throw new IllegalArgumentException(
|
||||
"filerChain " + proto.getName() + " has non-unique filter name:" + filter.getName());
|
||||
}
|
||||
validateFilter(filter);
|
||||
}
|
||||
return new FilterChain(
|
||||
FilterChainMatch.fromEnvoyProtoFilterChainMatch(proto.getFilterChainMatch()),
|
||||
getTlsContextFromFilterChain(proto),
|
||||
tlsContextManager
|
||||
);
|
||||
}
|
||||
|
||||
private static void validateFilter(Filter filter)
|
||||
throws InvalidProtocolBufferException, IllegalArgumentException {
|
||||
if (filter.hasConfigDiscovery()) {
|
||||
throw new IllegalArgumentException(
|
||||
"filter " + filter.getName() + " with config_discovery not supported");
|
||||
}
|
||||
if (!filter.hasTypedConfig()) {
|
||||
throw new IllegalArgumentException(
|
||||
"filter " + filter.getName() + " expected to have typed_config");
|
||||
}
|
||||
Any any = filter.getTypedConfig();
|
||||
if (!any.getTypeUrl().equals(ClientXdsClient.TYPE_URL_HTTP_CONNECTION_MANAGER)) {
|
||||
throw new IllegalArgumentException(
|
||||
"filter " + filter.getName() + " with unsupported typed_config type:" + any
|
||||
.getTypeUrl());
|
||||
}
|
||||
validateHttpConnectionManager(any.unpack(HttpConnectionManager.class));
|
||||
}
|
||||
|
||||
private static void validateHttpConnectionManager(HttpConnectionManager hcm)
|
||||
throws IllegalArgumentException {
|
||||
List<HttpFilter> httpFilters = hcm.getHttpFiltersList();
|
||||
HashSet<String> uniqueNames = new HashSet<>();
|
||||
for (HttpFilter httpFilter : httpFilters) {
|
||||
String httpFilterName = httpFilter.getName();
|
||||
if (!uniqueNames.add(httpFilterName)) {
|
||||
throw new IllegalArgumentException(
|
||||
"http-connection-manager has non-unique http-filter name:" + httpFilterName);
|
||||
}
|
||||
if (!httpFilter.getIsOptional()) {
|
||||
if (httpFilter.hasConfigDiscovery()) {
|
||||
throw new IllegalArgumentException(
|
||||
"http-connection-manager http-filter " + httpFilterName
|
||||
+ " uses config-discovery which is unsupported");
|
||||
}
|
||||
if (httpFilter.hasTypedConfig()) {
|
||||
Any any = httpFilter.getTypedConfig();
|
||||
if (!any.getTypeUrl()
|
||||
.equals("type.googleapis.com/envoy.extensions.filters.http.router.v3.Router")) {
|
||||
throw new IllegalArgumentException(
|
||||
"http-connection-manager http-filter " + httpFilterName
|
||||
+ " has unsupported typed-config type:" + any.getTypeUrl());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"http-connection-manager http-filter "
|
||||
+ httpFilterName
|
||||
+ " should have typed-config type "
|
||||
+ "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static DownstreamTlsContext getTlsContextFromFilterChain(
|
||||
io.envoyproxy.envoy.config.listener.v3.FilterChain filterChain)
|
||||
throws InvalidProtocolBufferException {
|
||||
if (filterChain.hasTransportSocket()
|
||||
&& TRANSPORT_SOCKET_NAME_TLS.equals(filterChain.getTransportSocket().getName())) {
|
||||
Any any = filterChain.getTransportSocket().getTypedConfig();
|
||||
return DownstreamTlsContext.fromEnvoyProtoDownstreamTlsContext(
|
||||
io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext.parseFrom(
|
||||
any.getValue()));
|
||||
}
|
||||
return null;
|
||||
String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public FilterChainMatch getFilterChainMatch() {
|
||||
return filterChainMatch;
|
||||
}
|
||||
|
||||
HttpConnectionManager getHttpConnectionManager() {
|
||||
return httpConnectionManager;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SslContextProviderSupplier getSslContextProviderSupplier() {
|
||||
return sslContextProviderSupplier;
|
||||
}
|
||||
|
|
@ -501,21 +364,26 @@ public final class EnvoyServerProtoData {
|
|||
return false;
|
||||
}
|
||||
FilterChain that = (FilterChain) o;
|
||||
return java.util.Objects.equals(filterChainMatch, that.filterChainMatch)
|
||||
&& java.util.Objects.equals(sslContextProviderSupplier, that.sslContextProviderSupplier);
|
||||
return Objects.equals(name, that.name)
|
||||
&& Objects.equals(filterChainMatch, that.filterChainMatch)
|
||||
&& Objects.equals(httpConnectionManager, that.httpConnectionManager)
|
||||
&& Objects.equals(sslContextProviderSupplier, that.sslContextProviderSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return java.util.Objects.hash(filterChainMatch, sslContextProviderSupplier);
|
||||
return Objects.hash(
|
||||
name, filterChainMatch, httpConnectionManager, sslContextProviderSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "FilterChain{"
|
||||
+ "filterChainMatch=" + filterChainMatch
|
||||
+ ", sslContextProviderSupplier=" + sslContextProviderSupplier
|
||||
+ '}';
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("name", name)
|
||||
.add("filterChainMatch", filterChainMatch)
|
||||
.add("httpConnectionManager", httpConnectionManager)
|
||||
.add("sslContextProviderSupplier", sslContextProviderSupplier)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -528,73 +396,22 @@ public final class EnvoyServerProtoData {
|
|||
@Nullable
|
||||
private final String address;
|
||||
private final List<FilterChain> filterChains;
|
||||
@Nullable
|
||||
private final FilterChain defaultFilterChain;
|
||||
|
||||
@VisibleForTesting
|
||||
Listener(String name, String address,
|
||||
List<FilterChain> filterChains, FilterChain defaultFilterChain) {
|
||||
this.name = name;
|
||||
Listener(String name, @Nullable String address,
|
||||
List<FilterChain> filterChains, @Nullable FilterChain defaultFilterChain) {
|
||||
this.name = checkNotNull(name, "name");
|
||||
this.address = address;
|
||||
this.filterChains = Collections.unmodifiableList(filterChains);
|
||||
this.filterChains = Collections.unmodifiableList(checkNotNull(filterChains, "filterChains"));
|
||||
this.defaultFilterChain = defaultFilterChain;
|
||||
}
|
||||
|
||||
private static String convertEnvoyAddressToString(Address proto) {
|
||||
if (proto.hasSocketAddress()) {
|
||||
SocketAddress socketAddress = proto.getSocketAddress();
|
||||
String address = socketAddress.getAddress();
|
||||
switch (socketAddress.getPortSpecifierCase()) {
|
||||
case NAMED_PORT:
|
||||
return address + ":" + socketAddress.getNamedPort();
|
||||
case PORT_VALUE:
|
||||
return address + ":" + socketAddress.getPortValue();
|
||||
default:
|
||||
return address;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static Listener fromEnvoyProtoListener(io.envoyproxy.envoy.config.listener.v3.Listener proto,
|
||||
TlsContextManager tlsContextManager)
|
||||
throws InvalidProtocolBufferException {
|
||||
if (!proto.getTrafficDirection().equals(TrafficDirection.INBOUND)) {
|
||||
throw new IllegalArgumentException("Listener " + proto.getName() + " is not INBOUND");
|
||||
}
|
||||
if (!proto.getListenerFiltersList().isEmpty()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Listener " + proto.getName() + " cannot have listener_filters");
|
||||
}
|
||||
if (proto.hasUseOriginalDst()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Listener " + proto.getName() + " cannot have use_original_dst set to true");
|
||||
}
|
||||
List<FilterChain> filterChains = validateAndSelectFilterChains(proto.getFilterChainsList(),
|
||||
tlsContextManager);
|
||||
return new Listener(
|
||||
proto.getName(),
|
||||
convertEnvoyAddressToString(proto.getAddress()),
|
||||
filterChains, FilterChain
|
||||
.fromEnvoyProtoFilterChain(proto.getDefaultFilterChain(), tlsContextManager, true));
|
||||
}
|
||||
|
||||
private static List<FilterChain> validateAndSelectFilterChains(
|
||||
List<io.envoyproxy.envoy.config.listener.v3.FilterChain> inputFilterChains,
|
||||
TlsContextManager tlsContextManager)
|
||||
throws InvalidProtocolBufferException {
|
||||
List<FilterChain> filterChains = new ArrayList<>(inputFilterChains.size());
|
||||
for (io.envoyproxy.envoy.config.listener.v3.FilterChain filterChain :
|
||||
inputFilterChains) {
|
||||
filterChains
|
||||
.add(FilterChain.fromEnvoyProtoFilterChain(filterChain, tlsContextManager, false));
|
||||
}
|
||||
return filterChains;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
|
@ -603,6 +420,7 @@ public final class EnvoyServerProtoData {
|
|||
return filterChains;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public FilterChain getDefaultFilterChain() {
|
||||
return defaultFilterChain;
|
||||
}
|
||||
|
|
@ -629,18 +447,12 @@ public final class EnvoyServerProtoData {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Listener{"
|
||||
+ "name='"
|
||||
+ name
|
||||
+ '\''
|
||||
+ ", address='"
|
||||
+ address
|
||||
+ '\''
|
||||
+ ", filterChains="
|
||||
+ filterChains
|
||||
+ ", defaultFilterChain="
|
||||
+ defaultFilterChain
|
||||
+ '}';
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("name", name)
|
||||
.add("address", address)
|
||||
.add("filterChains", filterChains)
|
||||
.add("defaultFilterChain", defaultFilterChain)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2021 The gRPC Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.grpc.xds;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import io.grpc.xds.Filter.NamedFilterConfig;
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* HttpConnectionManager is a network filter for proxying HTTP requests.
|
||||
*/
|
||||
@AutoValue
|
||||
abstract class HttpConnectionManager {
|
||||
// Total number of nanoseconds to keep alive an HTTP request/response stream.
|
||||
abstract long httpMaxStreamDurationNano();
|
||||
|
||||
// Name of the route configuration to be used for RDS resource discovery.
|
||||
@Nullable
|
||||
abstract String rdsName();
|
||||
|
||||
// List of virtual hosts that make up the route table.
|
||||
@Nullable
|
||||
abstract ImmutableList<VirtualHost> virtualHosts();
|
||||
|
||||
// List of http filter configs. Null if HttpFilter support is not enabled.
|
||||
@Nullable
|
||||
abstract ImmutableList<NamedFilterConfig> httpFilterConfigs();
|
||||
|
||||
static HttpConnectionManager forRdsName(long httpMaxStreamDurationNano, String rdsName,
|
||||
@Nullable List<NamedFilterConfig> httpFilterConfigs) {
|
||||
checkNotNull(rdsName, "rdsName");
|
||||
return create(httpMaxStreamDurationNano, rdsName, null, httpFilterConfigs);
|
||||
}
|
||||
|
||||
static HttpConnectionManager forVirtualHosts(long httpMaxStreamDurationNano,
|
||||
List<VirtualHost> virtualHosts, @Nullable List<NamedFilterConfig> httpFilterConfigs) {
|
||||
checkNotNull(virtualHosts, "virtualHosts");
|
||||
return create(httpMaxStreamDurationNano, null, virtualHosts,
|
||||
httpFilterConfigs);
|
||||
}
|
||||
|
||||
private static HttpConnectionManager create(long httpMaxStreamDurationNano,
|
||||
@Nullable String rdsName, @Nullable List<VirtualHost> virtualHosts,
|
||||
@Nullable List<NamedFilterConfig> httpFilterConfigs) {
|
||||
return new AutoValue_HttpConnectionManager(
|
||||
httpMaxStreamDurationNano, rdsName,
|
||||
virtualHosts == null ? null : ImmutableList.copyOf(virtualHosts),
|
||||
httpFilterConfigs == null ? null : ImmutableList.copyOf(httpFilterConfigs));
|
||||
}
|
||||
}
|
||||
|
|
@ -19,14 +19,16 @@ package io.grpc.xds;
|
|||
import com.google.protobuf.Message;
|
||||
import io.grpc.ClientInterceptor;
|
||||
import io.grpc.LoadBalancer.PickSubchannelArgs;
|
||||
import io.grpc.ServerInterceptor;
|
||||
import io.grpc.xds.Filter.ClientInterceptorBuilder;
|
||||
import io.grpc.xds.Filter.ServerInterceptorBuilder;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Router filter implementation. Currently this filter does not parse any field in the config.
|
||||
*/
|
||||
enum RouterFilter implements Filter, ClientInterceptorBuilder {
|
||||
enum RouterFilter implements Filter, ClientInterceptorBuilder, ServerInterceptorBuilder {
|
||||
INSTANCE;
|
||||
|
||||
static final String TYPE_URL =
|
||||
|
|
@ -66,4 +68,11 @@ enum RouterFilter implements Filter, ClientInterceptorBuilder {
|
|||
ScheduledExecutorService scheduler) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ServerInterceptor buildServerInterceptor(
|
||||
FilterConfig config, @Nullable Filter.FilterConfig overrideConfig) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,12 +57,23 @@ abstract class VirtualHost {
|
|||
abstract static class Route {
|
||||
abstract RouteMatch routeMatch();
|
||||
|
||||
@Nullable
|
||||
abstract RouteAction routeAction();
|
||||
|
||||
abstract ImmutableMap<String, FilterConfig> filterConfigOverrides();
|
||||
|
||||
static Route create(
|
||||
RouteMatch routeMatch, RouteAction routeAction,
|
||||
static Route forAction(RouteMatch routeMatch, RouteAction routeAction,
|
||||
Map<String, FilterConfig> filterConfigOverrides) {
|
||||
return create(routeMatch, routeAction, filterConfigOverrides);
|
||||
}
|
||||
|
||||
static Route forNonForwardingAction(RouteMatch routeMatch,
|
||||
Map<String, FilterConfig> filterConfigOverrides) {
|
||||
return create(routeMatch, null, filterConfigOverrides);
|
||||
}
|
||||
|
||||
private static Route create(
|
||||
RouteMatch routeMatch, @Nullable RouteAction routeAction,
|
||||
Map<String, FilterConfig> filterConfigOverrides) {
|
||||
return new AutoValue_VirtualHost_Route(
|
||||
routeMatch, routeAction, ImmutableMap.copyOf(filterConfigOverrides));
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.MoreObjects.ToStringHelper;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.protobuf.Any;
|
||||
import io.grpc.Status;
|
||||
|
|
@ -29,7 +28,6 @@ import io.grpc.xds.Endpoints.DropOverload;
|
|||
import io.grpc.xds.Endpoints.LocalityLbEndpoints;
|
||||
import io.grpc.xds.EnvoyServerProtoData.Listener;
|
||||
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
|
||||
import io.grpc.xds.Filter.NamedFilterConfig;
|
||||
import io.grpc.xds.LoadStatsManager2.ClusterDropStats;
|
||||
import io.grpc.xds.LoadStatsManager2.ClusterLocalityStats;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -48,92 +46,25 @@ import javax.annotation.Nullable;
|
|||
*/
|
||||
abstract class XdsClient {
|
||||
|
||||
static final class LdsUpdate implements ResourceUpdate {
|
||||
// Total number of nanoseconds to keep alive an HTTP request/response stream.
|
||||
final long httpMaxStreamDurationNano;
|
||||
// The name of the route configuration to be used for RDS resource discovery.
|
||||
@AutoValue
|
||||
abstract static class LdsUpdate implements ResourceUpdate {
|
||||
// Http level api listener configuration.
|
||||
@Nullable
|
||||
final String rdsName;
|
||||
// The list virtual hosts that make up the route table.
|
||||
abstract HttpConnectionManager httpConnectionManager();
|
||||
|
||||
// Tcp level listener configuration.
|
||||
@Nullable
|
||||
final List<VirtualHost> virtualHosts;
|
||||
// Filter instance names. Null if HttpFilter support is not enabled.
|
||||
@Nullable final List<NamedFilterConfig> filterChain;
|
||||
// Server side Listener.
|
||||
@Nullable
|
||||
final Listener listener;
|
||||
abstract Listener listener();
|
||||
|
||||
LdsUpdate(
|
||||
long httpMaxStreamDurationNano, String rdsName,
|
||||
@Nullable List<NamedFilterConfig> filterChain) {
|
||||
this(httpMaxStreamDurationNano, rdsName, null, filterChain);
|
||||
static LdsUpdate forApiListener(HttpConnectionManager httpConnectionManager) {
|
||||
checkNotNull(httpConnectionManager, "httpConnectionManager");
|
||||
return new AutoValue_XdsClient_LdsUpdate(httpConnectionManager, null);
|
||||
}
|
||||
|
||||
LdsUpdate(
|
||||
long httpMaxStreamDurationNano, List<VirtualHost> virtualHosts,
|
||||
@Nullable List<NamedFilterConfig> filterChain) {
|
||||
this(httpMaxStreamDurationNano, null, virtualHosts, filterChain);
|
||||
static LdsUpdate forTcpListener(Listener listener) {
|
||||
checkNotNull(listener, "listener");
|
||||
return new AutoValue_XdsClient_LdsUpdate(null, listener);
|
||||
}
|
||||
|
||||
private LdsUpdate(
|
||||
long httpMaxStreamDurationNano, @Nullable String rdsName,
|
||||
@Nullable List<VirtualHost> virtualHosts, @Nullable List<NamedFilterConfig> filterChain) {
|
||||
this.httpMaxStreamDurationNano = httpMaxStreamDurationNano;
|
||||
this.rdsName = rdsName;
|
||||
this.virtualHosts = virtualHosts == null
|
||||
? null : Collections.unmodifiableList(new ArrayList<>(virtualHosts));
|
||||
this.filterChain = filterChain == null ? null : Collections.unmodifiableList(filterChain);
|
||||
this.listener = null;
|
||||
}
|
||||
|
||||
LdsUpdate(Listener listener) {
|
||||
this.listener = listener;
|
||||
this.httpMaxStreamDurationNano = 0L;
|
||||
this.rdsName = null;
|
||||
this.filterChain = null;
|
||||
this.virtualHosts = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(
|
||||
httpMaxStreamDurationNano, rdsName, virtualHosts, filterChain, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
LdsUpdate that = (LdsUpdate) o;
|
||||
return httpMaxStreamDurationNano == that.httpMaxStreamDurationNano
|
||||
&& Objects.equals(rdsName, that.rdsName)
|
||||
&& Objects.equals(virtualHosts, that.virtualHosts)
|
||||
&& Objects.equals(filterChain, that.filterChain)
|
||||
&& Objects.equals(listener, that.listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ToStringHelper toStringHelper = MoreObjects.toStringHelper(this);
|
||||
toStringHelper.add("httpMaxStreamDurationNano", httpMaxStreamDurationNano);
|
||||
if (rdsName != null) {
|
||||
toStringHelper.add("rdsName", rdsName);
|
||||
} else {
|
||||
toStringHelper.add("virtualHosts", virtualHosts);
|
||||
}
|
||||
if (filterChain != null) {
|
||||
toStringHelper.add("filterChain", filterChain);
|
||||
}
|
||||
if (listener != null) {
|
||||
toStringHelper.add("listener", listener);
|
||||
}
|
||||
return toStringHelper.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class RdsUpdate implements ResourceUpdate {
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ public final class XdsClientWrapperForServerSds {
|
|||
new XdsClient.LdsResourceWatcher() {
|
||||
@Override
|
||||
public void onChanged(XdsClient.LdsUpdate update) {
|
||||
releaseOldSuppliers(curListener.getAndSet(update.listener));
|
||||
releaseOldSuppliers(curListener.getAndSet(update.listener()));
|
||||
reportSuccess();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -359,6 +359,10 @@ final class XdsNameResolver extends NameResolver {
|
|||
return Result.forError(
|
||||
Status.UNAVAILABLE.withDescription("Could not find xDS route matching RPC"));
|
||||
}
|
||||
if (selectedRoute.routeAction() == null) {
|
||||
return Result.forError(Status.UNAVAILABLE.withDescription(
|
||||
"Could not route RPC to Route with non-forwarding action"));
|
||||
}
|
||||
RouteAction action = selectedRoute.routeAction();
|
||||
if (action.cluster() != null) {
|
||||
cluster = action.cluster();
|
||||
|
|
@ -648,14 +652,17 @@ final class XdsNameResolver extends NameResolver {
|
|||
return;
|
||||
}
|
||||
logger.log(XdsLogLevel.INFO, "Receive LDS resource update: {0}", update);
|
||||
List<VirtualHost> virtualHosts = update.virtualHosts;
|
||||
String rdsName = update.rdsName;
|
||||
HttpConnectionManager httpConnectionManager = update.httpConnectionManager();
|
||||
List<VirtualHost> virtualHosts = httpConnectionManager.virtualHosts();
|
||||
String rdsName = httpConnectionManager.rdsName();
|
||||
cleanUpRouteDiscoveryState();
|
||||
if (virtualHosts != null) {
|
||||
updateRoutes(virtualHosts, update.httpMaxStreamDurationNano, update.filterChain);
|
||||
updateRoutes(virtualHosts, httpConnectionManager.httpMaxStreamDurationNano(),
|
||||
httpConnectionManager.httpFilterConfigs());
|
||||
} else {
|
||||
routeDiscoveryState = new RouteDiscoveryState(
|
||||
rdsName, update.httpMaxStreamDurationNano, update.filterChain);
|
||||
rdsName, httpConnectionManager.httpMaxStreamDurationNano(),
|
||||
httpConnectionManager.httpFilterConfigs());
|
||||
logger.log(XdsLogLevel.INFO, "Start watching RDS resource {0}", rdsName);
|
||||
xdsClient.watchRdsResource(rdsName, routeDiscoveryState);
|
||||
}
|
||||
|
|
@ -739,11 +746,13 @@ final class XdsNameResolver extends NameResolver {
|
|||
Set<String> clusters = new HashSet<>();
|
||||
for (Route route : routes) {
|
||||
RouteAction action = route.routeAction();
|
||||
if (action.cluster() != null) {
|
||||
clusters.add(action.cluster());
|
||||
} else if (action.weightedClusters() != null) {
|
||||
for (ClusterWeight weighedCluster : action.weightedClusters()) {
|
||||
clusters.add(weighedCluster.name());
|
||||
if (action != null) {
|
||||
if (action.cluster() != null) {
|
||||
clusters.add(action.cluster());
|
||||
} else if (action.weightedClusters() != null) {
|
||||
for (ClusterWeight weighedCluster : action.weightedClusters()) {
|
||||
clusters.add(weighedCluster.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import io.envoyproxy.envoy.config.cluster.v3.Cluster.RingHashLbConfig.HashFuncti
|
|||
import io.envoyproxy.envoy.config.core.v3.Address;
|
||||
import io.envoyproxy.envoy.config.core.v3.AggregatedConfigSource;
|
||||
import io.envoyproxy.envoy.config.core.v3.ConfigSource;
|
||||
import io.envoyproxy.envoy.config.core.v3.ExtensionConfigSource;
|
||||
import io.envoyproxy.envoy.config.core.v3.HttpProtocolOptions;
|
||||
import io.envoyproxy.envoy.config.core.v3.Locality;
|
||||
import io.envoyproxy.envoy.config.core.v3.RuntimeFractionalPercent;
|
||||
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
|
||||
|
|
@ -47,8 +47,14 @@ import io.envoyproxy.envoy.config.listener.v3.FilterChain;
|
|||
import io.envoyproxy.envoy.config.listener.v3.FilterChainMatch;
|
||||
import io.envoyproxy.envoy.config.listener.v3.Listener;
|
||||
import io.envoyproxy.envoy.config.listener.v3.ListenerFilter;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Permission;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Policy;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.Principal;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.RBAC;
|
||||
import io.envoyproxy.envoy.config.rbac.v3.RBAC.Action;
|
||||
import io.envoyproxy.envoy.config.route.v3.DirectResponseAction;
|
||||
import io.envoyproxy.envoy.config.route.v3.FilterAction;
|
||||
import io.envoyproxy.envoy.config.route.v3.NonForwardingAction;
|
||||
import io.envoyproxy.envoy.config.route.v3.RedirectAction;
|
||||
import io.envoyproxy.envoy.config.route.v3.RouteAction.HashPolicy.ConnectionProperties;
|
||||
import io.envoyproxy.envoy.config.route.v3.RouteAction.HashPolicy.FilterState;
|
||||
|
|
@ -57,21 +63,23 @@ import io.envoyproxy.envoy.config.route.v3.RouteAction.HashPolicy.QueryParameter
|
|||
import io.envoyproxy.envoy.config.route.v3.RouteAction.MaxStreamDuration;
|
||||
import io.envoyproxy.envoy.config.route.v3.WeightedCluster;
|
||||
import io.envoyproxy.envoy.extensions.filters.common.fault.v3.FaultDelay;
|
||||
import io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort;
|
||||
import io.envoyproxy.envoy.extensions.filters.http.fault.v3.HTTPFault;
|
||||
import io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBACPerRoute;
|
||||
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.HttpFilter;
|
||||
import io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.Rds;
|
||||
import io.envoyproxy.envoy.type.matcher.v3.RegexMatchAndSubstitute;
|
||||
import io.envoyproxy.envoy.type.matcher.v3.RegexMatcher;
|
||||
import io.envoyproxy.envoy.type.matcher.v3.RegexMatcher.GoogleRE2;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType;
|
||||
import io.envoyproxy.envoy.type.v3.Int64Range;
|
||||
import io.grpc.Status.Code;
|
||||
import io.grpc.xds.ClientXdsClient.ResourceInvalidException;
|
||||
import io.grpc.xds.ClientXdsClient.StructOrError;
|
||||
import io.grpc.xds.Endpoints.LbEndpoint;
|
||||
import io.grpc.xds.Endpoints.LocalityLbEndpoints;
|
||||
import io.grpc.xds.FaultConfig.FaultAbort;
|
||||
import io.grpc.xds.Filter.FilterConfig;
|
||||
import io.grpc.xds.VirtualHost.Route;
|
||||
import io.grpc.xds.VirtualHost.Route.RouteAction;
|
||||
|
|
@ -100,6 +108,7 @@ public class ClientXdsClientDataTest {
|
|||
@SuppressWarnings("deprecation") // https://github.com/grpc/grpc-java/issues/7467
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
private final FilterRegistry filterRegistry = FilterRegistry.newRegistry();
|
||||
|
||||
@Test
|
||||
public void parseRoute_withRouteAction() {
|
||||
|
|
@ -113,17 +122,36 @@ public class ClientXdsClientDataTest {
|
|||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setCluster("cluster-foo"))
|
||||
.build();
|
||||
StructOrError<Route> struct = ClientXdsClient.parseRoute(proto, false);
|
||||
StructOrError<Route> struct = ClientXdsClient.parseRoute(proto, filterRegistry, false);
|
||||
assertThat(struct.getErrorDetail()).isNull();
|
||||
assertThat(struct.getStruct())
|
||||
.isEqualTo(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.create(PathMatcher.fromPath("/service/method", false),
|
||||
Collections.<HeaderMatcher>emptyList(), null),
|
||||
RouteAction.forCluster("cluster-foo", Collections.<HashPolicy>emptyList(), null),
|
||||
ImmutableMap.<String, FilterConfig>of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseRoute_withNonForwardingAction() {
|
||||
io.envoyproxy.envoy.config.route.v3.Route proto =
|
||||
io.envoyproxy.envoy.config.route.v3.Route.newBuilder()
|
||||
.setName("route-blade")
|
||||
.setMatch(
|
||||
io.envoyproxy.envoy.config.route.v3.RouteMatch.newBuilder()
|
||||
.setPath("/service/method"))
|
||||
.setNonForwardingAction(NonForwardingAction.getDefaultInstance())
|
||||
.build();
|
||||
StructOrError<Route> struct = ClientXdsClient.parseRoute(proto, filterRegistry, false);
|
||||
assertThat(struct.getStruct())
|
||||
.isEqualTo(
|
||||
Route.forNonForwardingAction(
|
||||
RouteMatch.create(PathMatcher.fromPath("/service/method", false),
|
||||
Collections.<HeaderMatcher>emptyList(), null),
|
||||
ImmutableMap.<String, FilterConfig>of()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseRoute_withUnsupportedActionTypes() {
|
||||
StructOrError<Route> res;
|
||||
|
|
@ -133,9 +161,10 @@ public class ClientXdsClientDataTest {
|
|||
.setMatch(io.envoyproxy.envoy.config.route.v3.RouteMatch.newBuilder().setPath(""))
|
||||
.setRedirect(RedirectAction.getDefaultInstance())
|
||||
.build();
|
||||
res = ClientXdsClient.parseRoute(redirectRoute, false);
|
||||
res = ClientXdsClient.parseRoute(redirectRoute, filterRegistry, false);
|
||||
assertThat(res.getStruct()).isNull();
|
||||
assertThat(res.getErrorDetail()).isEqualTo("Unsupported action type: redirect");
|
||||
assertThat(res.getErrorDetail())
|
||||
.isEqualTo("Route [route-blade] with unknown action type: REDIRECT");
|
||||
|
||||
io.envoyproxy.envoy.config.route.v3.Route directResponseRoute =
|
||||
io.envoyproxy.envoy.config.route.v3.Route.newBuilder()
|
||||
|
|
@ -143,9 +172,10 @@ public class ClientXdsClientDataTest {
|
|||
.setMatch(io.envoyproxy.envoy.config.route.v3.RouteMatch.newBuilder().setPath(""))
|
||||
.setDirectResponse(DirectResponseAction.getDefaultInstance())
|
||||
.build();
|
||||
res = ClientXdsClient.parseRoute(directResponseRoute, false);
|
||||
res = ClientXdsClient.parseRoute(directResponseRoute, filterRegistry, false);
|
||||
assertThat(res.getStruct()).isNull();
|
||||
assertThat(res.getErrorDetail()).isEqualTo("Unsupported action type: direct_response");
|
||||
assertThat(res.getErrorDetail())
|
||||
.isEqualTo("Route [route-blade] with unknown action type: DIRECT_RESPONSE");
|
||||
|
||||
io.envoyproxy.envoy.config.route.v3.Route filterRoute =
|
||||
io.envoyproxy.envoy.config.route.v3.Route.newBuilder()
|
||||
|
|
@ -153,9 +183,10 @@ public class ClientXdsClientDataTest {
|
|||
.setMatch(io.envoyproxy.envoy.config.route.v3.RouteMatch.newBuilder().setPath(""))
|
||||
.setFilterAction(FilterAction.getDefaultInstance())
|
||||
.build();
|
||||
res = ClientXdsClient.parseRoute(filterRoute, false);
|
||||
res = ClientXdsClient.parseRoute(filterRoute, filterRegistry, false);
|
||||
assertThat(res.getStruct()).isNull();
|
||||
assertThat(res.getErrorDetail()).isEqualTo("Unsupported action type: filter_action");
|
||||
assertThat(res.getErrorDetail())
|
||||
.isEqualTo("Route [route-blade] with unknown action type: FILTER_ACTION");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -173,7 +204,7 @@ public class ClientXdsClientDataTest {
|
|||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setCluster("cluster-foo"))
|
||||
.build();
|
||||
assertThat(ClientXdsClient.parseRoute(proto, false)).isNull();
|
||||
assertThat(ClientXdsClient.parseRoute(proto, filterRegistry, false)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -188,7 +219,7 @@ public class ClientXdsClientDataTest {
|
|||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setClusterHeader("cluster header")) // cluster_header action not supported
|
||||
.build();
|
||||
assertThat(ClientXdsClient.parseRoute(proto, false)).isNull();
|
||||
assertThat(ClientXdsClient.parseRoute(proto, filterRegistry, false)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -367,7 +398,8 @@ public class ClientXdsClientDataTest {
|
|||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setCluster("cluster-foo")
|
||||
.build();
|
||||
StructOrError<RouteAction> struct = ClientXdsClient.parseRouteAction(proto, false);
|
||||
StructOrError<RouteAction> struct =
|
||||
ClientXdsClient.parseRouteAction(proto, filterRegistry, false);
|
||||
assertThat(struct.getErrorDetail()).isNull();
|
||||
assertThat(struct.getStruct().cluster()).isEqualTo("cluster-foo");
|
||||
assertThat(struct.getStruct().weightedClusters()).isNull();
|
||||
|
|
@ -389,7 +421,8 @@ public class ClientXdsClientDataTest {
|
|||
.setName("cluster-bar")
|
||||
.setWeight(UInt32Value.newBuilder().setValue(70))))
|
||||
.build();
|
||||
StructOrError<RouteAction> struct = ClientXdsClient.parseRouteAction(proto, false);
|
||||
StructOrError<RouteAction> struct =
|
||||
ClientXdsClient.parseRouteAction(proto, filterRegistry, false);
|
||||
assertThat(struct.getErrorDetail()).isNull();
|
||||
assertThat(struct.getStruct().cluster()).isNull();
|
||||
assertThat(struct.getStruct().weightedClusters()).containsExactly(
|
||||
|
|
@ -407,7 +440,8 @@ public class ClientXdsClientDataTest {
|
|||
.setGrpcTimeoutHeaderMax(Durations.fromSeconds(5L))
|
||||
.setMaxStreamDuration(Durations.fromMillis(20L)))
|
||||
.build();
|
||||
StructOrError<RouteAction> struct = ClientXdsClient.parseRouteAction(proto, false);
|
||||
StructOrError<RouteAction> struct =
|
||||
ClientXdsClient.parseRouteAction(proto, filterRegistry, false);
|
||||
assertThat(struct.getStruct().timeoutNano()).isEqualTo(TimeUnit.SECONDS.toNanos(5L));
|
||||
}
|
||||
|
||||
|
|
@ -420,7 +454,8 @@ public class ClientXdsClientDataTest {
|
|||
MaxStreamDuration.newBuilder()
|
||||
.setMaxStreamDuration(Durations.fromSeconds(5L)))
|
||||
.build();
|
||||
StructOrError<RouteAction> struct = ClientXdsClient.parseRouteAction(proto, false);
|
||||
StructOrError<RouteAction> struct =
|
||||
ClientXdsClient.parseRouteAction(proto, filterRegistry, false);
|
||||
assertThat(struct.getStruct().timeoutNano()).isEqualTo(TimeUnit.SECONDS.toNanos(5L));
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +465,8 @@ public class ClientXdsClientDataTest {
|
|||
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
|
||||
.setCluster("cluster-foo")
|
||||
.build();
|
||||
StructOrError<RouteAction> struct = ClientXdsClient.parseRouteAction(proto, false);
|
||||
StructOrError<RouteAction> struct =
|
||||
ClientXdsClient.parseRouteAction(proto, filterRegistry, false);
|
||||
assertThat(struct.getStruct().timeoutNano()).isNull();
|
||||
}
|
||||
|
||||
|
|
@ -465,7 +501,8 @@ public class ClientXdsClientDataTest {
|
|||
.setQueryParameter(
|
||||
QueryParameter.newBuilder().setName("param"))) // unsupported
|
||||
.build();
|
||||
StructOrError<RouteAction> struct = ClientXdsClient.parseRouteAction(proto, false);
|
||||
StructOrError<RouteAction> struct =
|
||||
ClientXdsClient.parseRouteAction(proto, filterRegistry, false);
|
||||
List<HashPolicy> policies = struct.getStruct().hashPolicies();
|
||||
assertThat(policies).hasSize(2);
|
||||
assertThat(policies.get(0).type()).isEqualTo(HashPolicy.Type.HEADER);
|
||||
|
|
@ -485,39 +522,12 @@ public class ClientXdsClientDataTest {
|
|||
.setName("cluster-foo")
|
||||
.setWeight(UInt32Value.newBuilder().setValue(30))
|
||||
.build();
|
||||
ClusterWeight clusterWeight = ClientXdsClient.parseClusterWeight(proto, false).getStruct();
|
||||
ClusterWeight clusterWeight =
|
||||
ClientXdsClient.parseClusterWeight(proto, filterRegistry, false).getStruct();
|
||||
assertThat(clusterWeight.name()).isEqualTo("cluster-foo");
|
||||
assertThat(clusterWeight.weight()).isEqualTo(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFaultAbort_withHttpStatus() {
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort proto =
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort.newBuilder()
|
||||
.setPercentage(FractionalPercent.newBuilder()
|
||||
.setNumerator(100).setDenominator(DenominatorType.TEN_THOUSAND))
|
||||
.setHttpStatus(400).build();
|
||||
FaultAbort res = FaultFilter.parseFaultAbort(proto).config;
|
||||
assertThat(res.percent().numerator()).isEqualTo(100);
|
||||
assertThat(res.percent().denominatorType())
|
||||
.isEqualTo(FaultConfig.FractionalPercent.DenominatorType.TEN_THOUSAND);
|
||||
assertThat(res.status().getCode()).isEqualTo(Code.INTERNAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFaultAbort_withGrpcStatus() {
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort proto =
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort.newBuilder()
|
||||
.setPercentage(FractionalPercent.newBuilder()
|
||||
.setNumerator(600).setDenominator(DenominatorType.MILLION))
|
||||
.setGrpcStatus(Code.DEADLINE_EXCEEDED.value()).build();
|
||||
FaultAbort faultAbort = FaultFilter.parseFaultAbort(proto).config;
|
||||
assertThat(faultAbort.percent().numerator()).isEqualTo(600);
|
||||
assertThat(faultAbort.percent().denominatorType())
|
||||
.isEqualTo(FaultConfig.FractionalPercent.DenominatorType.MILLION);
|
||||
assertThat(faultAbort.status().getCode()).isEqualTo(Code.DEADLINE_EXCEEDED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseLocalityLbEndpoints_withHealthyEndpoints() {
|
||||
io.envoyproxy.envoy.config.endpoint.v3.LocalityLbEndpoints proto =
|
||||
|
|
@ -637,7 +647,7 @@ public class ClientXdsClientDataTest {
|
|||
.setIsOptional(true)
|
||||
.setTypedConfig(Any.pack(StringValue.of("unsupported")))
|
||||
.build();
|
||||
assertThat(ClientXdsClient.parseHttpFilter(httpFilter)).isNull();
|
||||
assertThat(ClientXdsClient.parseHttpFilter(httpFilter, filterRegistry, true)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -647,13 +657,181 @@ public class ClientXdsClientDataTest {
|
|||
.setName("unsupported.filter")
|
||||
.setTypedConfig(Any.pack(StringValue.of("string value")))
|
||||
.build();
|
||||
assertThat(ClientXdsClient.parseHttpFilter(httpFilter).getErrorDetail()).isEqualTo(
|
||||
"HttpFilter [unsupported.filter] is not optional and has an unsupported config type: "
|
||||
+ "type.googleapis.com/google.protobuf.StringValue");
|
||||
assertThat(ClientXdsClient.parseHttpFilter(httpFilter, filterRegistry, true)
|
||||
.getErrorDetail()).isEqualTo(
|
||||
"HttpFilter [unsupported.filter]"
|
||||
+ "(type.googleapis.com/google.protobuf.StringValue) is required but unsupported "
|
||||
+ "for client");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpFilter_routerFilterForClient() {
|
||||
filterRegistry.register(RouterFilter.INSTANCE);
|
||||
HttpFilter httpFilter =
|
||||
HttpFilter.newBuilder()
|
||||
.setIsOptional(false)
|
||||
.setName("envoy.router")
|
||||
.setTypedConfig(Any.pack(Router.getDefaultInstance()))
|
||||
.build();
|
||||
FilterConfig config = ClientXdsClient.parseHttpFilter(
|
||||
httpFilter, filterRegistry, true /* isForClient */).getStruct();
|
||||
assertThat(config.typeUrl()).isEqualTo(RouterFilter.TYPE_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpFilter_routerFilterForServer() {
|
||||
filterRegistry.register(RouterFilter.INSTANCE);
|
||||
HttpFilter httpFilter =
|
||||
HttpFilter.newBuilder()
|
||||
.setIsOptional(false)
|
||||
.setName("envoy.router")
|
||||
.setTypedConfig(Any.pack(Router.getDefaultInstance()))
|
||||
.build();
|
||||
FilterConfig config = ClientXdsClient.parseHttpFilter(
|
||||
httpFilter, filterRegistry, false /* isForClient */).getStruct();
|
||||
assertThat(config.typeUrl()).isEqualTo(RouterFilter.TYPE_URL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpFilter_faultConfigForClient() {
|
||||
filterRegistry.register(FaultFilter.INSTANCE);
|
||||
HttpFilter httpFilter =
|
||||
HttpFilter.newBuilder()
|
||||
.setIsOptional(false)
|
||||
.setName("envoy.fault")
|
||||
.setTypedConfig(
|
||||
Any.pack(
|
||||
HTTPFault.newBuilder()
|
||||
.setDelay(
|
||||
FaultDelay.newBuilder()
|
||||
.setFixedDelay(Durations.fromNanos(1234L)))
|
||||
.setAbort(
|
||||
FaultAbort.newBuilder()
|
||||
.setHttpStatus(300)
|
||||
.setPercentage(
|
||||
FractionalPercent.newBuilder()
|
||||
.setNumerator(10)
|
||||
.setDenominator(DenominatorType.HUNDRED)))
|
||||
.build()))
|
||||
.build();
|
||||
FilterConfig config = ClientXdsClient.parseHttpFilter(
|
||||
httpFilter, filterRegistry, true /* isForClient */).getStruct();
|
||||
assertThat(config).isInstanceOf(FaultConfig.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpFilter_faultConfigUnsupportedForServer() {
|
||||
filterRegistry.register(FaultFilter.INSTANCE);
|
||||
HttpFilter httpFilter =
|
||||
HttpFilter.newBuilder()
|
||||
.setIsOptional(false)
|
||||
.setName("envoy.fault")
|
||||
.setTypedConfig(
|
||||
Any.pack(
|
||||
HTTPFault.newBuilder()
|
||||
.setDelay(
|
||||
FaultDelay.newBuilder()
|
||||
.setFixedDelay(Durations.fromNanos(1234L)))
|
||||
.setAbort(
|
||||
FaultAbort.newBuilder()
|
||||
.setHttpStatus(300)
|
||||
.setPercentage(
|
||||
FractionalPercent.newBuilder()
|
||||
.setNumerator(10)
|
||||
.setDenominator(DenominatorType.HUNDRED)))
|
||||
.build()))
|
||||
.build();
|
||||
StructOrError<FilterConfig> config =
|
||||
ClientXdsClient.parseHttpFilter(httpFilter, filterRegistry, false /* isForClient */);
|
||||
assertThat(config.getErrorDetail()).isEqualTo(
|
||||
"HttpFilter [envoy.fault](" + FaultFilter.TYPE_URL + ") is required but "
|
||||
+ "unsupported for server");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpFilter_rbacConfigForServer() {
|
||||
filterRegistry.register(RbacFilter.INSTANCE);
|
||||
HttpFilter httpFilter =
|
||||
HttpFilter.newBuilder()
|
||||
.setIsOptional(false)
|
||||
.setName("envoy.auth")
|
||||
.setTypedConfig(
|
||||
Any.pack(
|
||||
io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder()
|
||||
.setRules(
|
||||
RBAC.newBuilder()
|
||||
.setAction(Action.ALLOW)
|
||||
.putPolicies(
|
||||
"allow-all",
|
||||
Policy.newBuilder()
|
||||
.addPrincipals(Principal.newBuilder().setAny(true))
|
||||
.addPermissions(Permission.newBuilder().setAny(true))
|
||||
.build())
|
||||
.build())
|
||||
.build()))
|
||||
.build();
|
||||
FilterConfig config = ClientXdsClient.parseHttpFilter(
|
||||
httpFilter, filterRegistry, false /* isForClient */).getStruct();
|
||||
assertThat(config).isInstanceOf(RbacConfig.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpFilter_rbacConfigUnsupportedForClient() {
|
||||
filterRegistry.register(RbacFilter.INSTANCE);
|
||||
HttpFilter httpFilter =
|
||||
HttpFilter.newBuilder()
|
||||
.setIsOptional(false)
|
||||
.setName("envoy.auth")
|
||||
.setTypedConfig(
|
||||
Any.pack(
|
||||
io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder()
|
||||
.setRules(
|
||||
RBAC.newBuilder()
|
||||
.setAction(Action.ALLOW)
|
||||
.putPolicies(
|
||||
"allow-all",
|
||||
Policy.newBuilder()
|
||||
.addPrincipals(Principal.newBuilder().setAny(true))
|
||||
.addPermissions(Permission.newBuilder().setAny(true))
|
||||
.build())
|
||||
.build())
|
||||
.build()))
|
||||
.build();
|
||||
StructOrError<FilterConfig> config =
|
||||
ClientXdsClient.parseHttpFilter(httpFilter, filterRegistry, true /* isForClient */);
|
||||
assertThat(config.getErrorDetail()).isEqualTo(
|
||||
"HttpFilter [envoy.auth](" + RbacFilter.TYPE_URL + ") is required but "
|
||||
+ "unsupported for client");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseOverrideRbacFilterConfig() {
|
||||
filterRegistry.register(RbacFilter.INSTANCE);
|
||||
RBACPerRoute rbacPerRoute =
|
||||
RBACPerRoute.newBuilder()
|
||||
.setRbac(
|
||||
io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder()
|
||||
.setRules(
|
||||
RBAC.newBuilder()
|
||||
.setAction(Action.ALLOW)
|
||||
.putPolicies(
|
||||
"allow-all",
|
||||
Policy.newBuilder()
|
||||
.addPrincipals(Principal.newBuilder().setAny(true))
|
||||
.addPermissions(Permission.newBuilder().setAny(true))
|
||||
.build())))
|
||||
.build();
|
||||
Map<String, Any> configOverrides = ImmutableMap.of("envoy.auth", Any.pack(rbacPerRoute));
|
||||
Map<String, FilterConfig> parsedConfigs =
|
||||
ClientXdsClient.parseOverrideFilterConfigs(configOverrides, filterRegistry).getStruct();
|
||||
assertThat(parsedConfigs).hasSize(1);
|
||||
assertThat(parsedConfigs).containsKey("envoy.auth");
|
||||
assertThat(parsedConfigs.get("envoy.auth")).isInstanceOf(RbacConfig.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseOverrideFilterConfigs_unsupportedButOptional() {
|
||||
filterRegistry.register(FaultFilter.INSTANCE);
|
||||
HTTPFault httpFault = HTTPFault.newBuilder()
|
||||
.setDelay(FaultDelay.newBuilder().setFixedDelay(Durations.fromNanos(3000)))
|
||||
.build();
|
||||
|
|
@ -665,13 +843,14 @@ public class ClientXdsClientDataTest {
|
|||
.setIsOptional(true).setConfig(Any.pack(StringValue.of("string value")))
|
||||
.build()));
|
||||
Map<String, FilterConfig> parsedConfigs =
|
||||
ClientXdsClient.parseOverrideFilterConfigs(configOverrides).getStruct();
|
||||
ClientXdsClient.parseOverrideFilterConfigs(configOverrides, filterRegistry).getStruct();
|
||||
assertThat(parsedConfigs).hasSize(1);
|
||||
assertThat(parsedConfigs).containsKey("envoy.fault");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseOverrideFilterConfigs_unsupportedAndRequired() {
|
||||
filterRegistry.register(FaultFilter.INSTANCE);
|
||||
HTTPFault httpFault = HTTPFault.newBuilder()
|
||||
.setDelay(FaultDelay.newBuilder().setFixedDelay(Durations.fromNanos(3000)))
|
||||
.build();
|
||||
|
|
@ -682,20 +861,66 @@ public class ClientXdsClientDataTest {
|
|||
Any.pack(io.envoyproxy.envoy.config.route.v3.FilterConfig.newBuilder()
|
||||
.setIsOptional(false).setConfig(Any.pack(StringValue.of("string value")))
|
||||
.build()));
|
||||
assertThat(ClientXdsClient.parseOverrideFilterConfigs(configOverrides).getErrorDetail())
|
||||
.isEqualTo(
|
||||
"HttpFilter [unsupported.filter] is not optional and has an unsupported config type: "
|
||||
+ "type.googleapis.com/google.protobuf.StringValue");
|
||||
assertThat(ClientXdsClient.parseOverrideFilterConfigs(configOverrides, filterRegistry)
|
||||
.getErrorDetail()).isEqualTo(
|
||||
"HttpFilter [unsupported.filter]"
|
||||
+ "(type.googleapis.com/google.protobuf.StringValue) is required but unsupported");
|
||||
|
||||
configOverrides = ImmutableMap.of(
|
||||
"envoy.fault",
|
||||
Any.pack(httpFault),
|
||||
"unsupported.filter",
|
||||
Any.pack(StringValue.of("string value")));
|
||||
assertThat(ClientXdsClient.parseOverrideFilterConfigs(configOverrides).getErrorDetail())
|
||||
.isEqualTo(
|
||||
"HttpFilter [unsupported.filter] is not optional and has an unsupported config type: "
|
||||
+ "type.googleapis.com/google.protobuf.StringValue");
|
||||
assertThat(ClientXdsClient.parseOverrideFilterConfigs(configOverrides, filterRegistry)
|
||||
.getErrorDetail()).isEqualTo(
|
||||
"HttpFilter [unsupported.filter]"
|
||||
+ "(type.googleapis.com/google.protobuf.StringValue) is required but unsupported");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpConnectionManager_xffNumTrustedHopsUnsupported()
|
||||
throws ResourceInvalidException {
|
||||
HttpConnectionManager hcm =
|
||||
HttpConnectionManager.newBuilder()
|
||||
.setXffNumTrustedHops(2)
|
||||
.build();
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage("HttpConnectionManager with xff_num_trusted_hops unsupported");
|
||||
ClientXdsClient.parseHttpConnectionManager(
|
||||
hcm, new HashSet<String>(), filterRegistry, false /* does not matter */,
|
||||
true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpConnectionManager_missingRdsAndInlinedRouteConfiguration()
|
||||
throws ResourceInvalidException {
|
||||
HttpConnectionManager hcm =
|
||||
HttpConnectionManager.newBuilder()
|
||||
.setCommonHttpProtocolOptions(
|
||||
HttpProtocolOptions.newBuilder()
|
||||
.setMaxStreamDuration(Durations.fromNanos(1000L)))
|
||||
.build();
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage("HttpConnectionManager neither has inlined route_config nor RDS");
|
||||
ClientXdsClient.parseHttpConnectionManager(
|
||||
hcm, new HashSet<String>(), filterRegistry, false /* does not matter */,
|
||||
true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseHttpConnectionManager_duplicateHttpFilters() throws ResourceInvalidException {
|
||||
HttpConnectionManager hcm =
|
||||
HttpConnectionManager.newBuilder()
|
||||
.addHttpFilters(
|
||||
HttpFilter.newBuilder().setName("envoy.filter.foo").setIsOptional(true))
|
||||
.addHttpFilters(
|
||||
HttpFilter.newBuilder().setName("envoy.filter.foo").setIsOptional(true))
|
||||
.build();
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage("HttpConnectionManager contains duplicate HttpFilter: envoy.filter.foo");
|
||||
ClientXdsClient.parseHttpConnectionManager(
|
||||
hcm, new HashSet<String>(), filterRegistry, true /* parseHttpFilter */,
|
||||
true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -773,250 +998,162 @@ public class ClientXdsClientDataTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_invalidTrafficDirection() {
|
||||
public void parseServerSideListener_invalidTrafficDirection() throws ResourceInvalidException {
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.OUTBOUND)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail()).isEqualTo("Listener listener1 is not INBOUND");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage("Listener listener1 with invalid traffic direction: OUTBOUND");
|
||||
ClientXdsClient.parseServerSideListener(
|
||||
listener, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_listenerFiltersPresent() {
|
||||
public void parseServerSideListener_listenerFiltersPresent() throws ResourceInvalidException {
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addListenerFilters(ListenerFilter.newBuilder().build())
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("Listener listener1 cannot have listener_filters");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage("Listener listener1 cannot have listener_filters");
|
||||
ClientXdsClient.parseServerSideListener(
|
||||
listener, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_useOriginalDst() {
|
||||
public void parseServerSideListener_useOriginalDst() throws ResourceInvalidException {
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.setUseOriginalDst(BoolValue.of(true))
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("Listener listener1 cannot have use_original_dst set to true");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage("Listener listener1 cannot have use_original_dst set to true");
|
||||
ClientXdsClient.parseServerSideListener(
|
||||
listener, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_noHcm() {
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(FilterChain.newBuilder().build())
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("filerChain has to have envoy.http_connection_manager");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_duplicateFilterName() {
|
||||
public void parseFilterChain_noHcm() throws ResourceInvalidException {
|
||||
FilterChain filterChain =
|
||||
buildFilterChain(
|
||||
Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.pack(HttpConnectionManager.getDefaultInstance()))
|
||||
.build(),
|
||||
Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.pack(HttpConnectionManager.getDefaultInstance()))
|
||||
.build());
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
FilterChain.newBuilder()
|
||||
.setName("filter-chain-foo")
|
||||
.setFilterChainMatch(FilterChainMatch.getDefaultInstance())
|
||||
.setTransportSocket(TransportSocket.getDefaultInstance())
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("filerChain has non-unique filter name:envoy.http_connection_manager");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage(
|
||||
"FilterChain filter-chain-foo missing required HttpConnectionManager filter");
|
||||
ClientXdsClient.parseFilterChain(
|
||||
filterChain, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_configDiscoveryFilter() {
|
||||
Filter filter =
|
||||
Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setConfigDiscovery(ExtensionConfigSource.newBuilder().build())
|
||||
public void parseFilterChain_duplicateFilter() throws ResourceInvalidException {
|
||||
Filter filter = buildHttpConnectionManagerFilter(
|
||||
HttpFilter.newBuilder().setName("http-filter-foo").setIsOptional(true).build());
|
||||
FilterChain filterChain =
|
||||
FilterChain.newBuilder()
|
||||
.setName("filter-chain-foo")
|
||||
.setFilterChainMatch(FilterChainMatch.getDefaultInstance())
|
||||
.setTransportSocket(TransportSocket.getDefaultInstance())
|
||||
.addAllFilters(Arrays.asList(filter, filter))
|
||||
.build();
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("filter envoy.http_connection_manager with config_discovery not supported");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage(
|
||||
"FilterChain filter-chain-foo with duplicated filter: envoy.http_connection_manager");
|
||||
ClientXdsClient.parseFilterChain(
|
||||
filterChain, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_expectTypedConfigFilter() {
|
||||
public void parseFilterChain_filterMissingTypedConfig() throws ResourceInvalidException {
|
||||
Filter filter = Filter.newBuilder().setName("envoy.http_connection_manager").build();
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
FilterChain filterChain =
|
||||
FilterChain.newBuilder()
|
||||
.setName("filter-chain-foo")
|
||||
.setFilterChainMatch(FilterChainMatch.getDefaultInstance())
|
||||
.setTransportSocket(TransportSocket.getDefaultInstance())
|
||||
.addFilters(filter)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("filter envoy.http_connection_manager expected to have typed_config");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage(
|
||||
"FilterChain filter-chain-foo contains filter envoy.http_connection_manager "
|
||||
+ "without typed_config");
|
||||
ClientXdsClient.parseFilterChain(
|
||||
filterChain, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_wrongTypeUrl() {
|
||||
public void parseFilterChain_unsupportedFilter() throws ResourceInvalidException {
|
||||
Filter filter =
|
||||
Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.newBuilder().setTypeUrl("badTypeUrl"))
|
||||
.setName("unsupported")
|
||||
.setTypedConfig(Any.newBuilder().setTypeUrl("unsupported-type-url"))
|
||||
.build();
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
FilterChain filterChain =
|
||||
FilterChain.newBuilder()
|
||||
.setName("filter-chain-foo")
|
||||
.setFilterChainMatch(FilterChainMatch.getDefaultInstance())
|
||||
.setTransportSocket(TransportSocket.getDefaultInstance())
|
||||
.addFilters(filter)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo(
|
||||
"filter envoy.http_connection_manager with unsupported typed_config type:badTypeUrl");
|
||||
thrown.expect(ResourceInvalidException.class);
|
||||
thrown.expectMessage(
|
||||
"FilterChain filter-chain-foo contains filter unsupported with unsupported "
|
||||
+ "typed_config type unsupported-type-url");
|
||||
ClientXdsClient.parseFilterChain(
|
||||
filterChain, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_duplicateHttpFilter() {
|
||||
Filter filter =
|
||||
buildHttpConnectionManager(
|
||||
"envoy.http_connection_manager",
|
||||
HttpFilter.newBuilder().setName("hf").setIsOptional(true).build(),
|
||||
HttpFilter.newBuilder().setName("hf").setIsOptional(true).build());
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
public void parseFilterChain_noName_generatedUuid() throws ResourceInvalidException {
|
||||
FilterChain filterChain1 =
|
||||
FilterChain.newBuilder()
|
||||
.setFilterChainMatch(FilterChainMatch.getDefaultInstance())
|
||||
.addFilters(buildHttpConnectionManagerFilter(
|
||||
HttpFilter.newBuilder()
|
||||
.setName("http-filter-foo")
|
||||
.setIsOptional(true)
|
||||
.build()))
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo("http-connection-manager has non-unique http-filter name:hf");
|
||||
FilterChain filterChain2 =
|
||||
FilterChain.newBuilder()
|
||||
.setFilterChainMatch(FilterChainMatch.getDefaultInstance())
|
||||
.addFilters(buildHttpConnectionManagerFilter(
|
||||
HttpFilter.newBuilder()
|
||||
.setName("http-filter-bar")
|
||||
.setIsOptional(true)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
EnvoyServerProtoData.FilterChain parsedFilterChain1 = ClientXdsClient.parseFilterChain(
|
||||
filterChain1, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
EnvoyServerProtoData.FilterChain parsedFilterChain2 = ClientXdsClient.parseFilterChain(
|
||||
filterChain2, new HashSet<String>(), null, filterRegistry, true /* does not matter */);
|
||||
assertThat(parsedFilterChain1.getName()).isNotEqualTo(parsedFilterChain2.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_configDiscoveryHttpFilter() {
|
||||
Filter filter =
|
||||
buildHttpConnectionManager(
|
||||
"envoy.http_connection_manager",
|
||||
HttpFilter.newBuilder()
|
||||
.setName("envoy.router")
|
||||
.setConfigDiscovery(ExtensionConfigSource.newBuilder().build())
|
||||
.build());
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo(
|
||||
"http-connection-manager http-filter envoy.router uses "
|
||||
+ "config-discovery which is unsupported");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_badTypeUrlHttpFilter() {
|
||||
HTTPFault fault = HTTPFault.newBuilder().build();
|
||||
Filter filter =
|
||||
buildHttpConnectionManager(
|
||||
"envoy.http_connection_manager",
|
||||
HttpFilter.newBuilder()
|
||||
.setName("envoy.router")
|
||||
.setTypedConfig(Any.pack(fault, "type.googleapis.com"))
|
||||
.build());
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo(
|
||||
"http-connection-manager http-filter envoy.router has unsupported typed-config type:"
|
||||
+ "type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseServerSideListener_missingTypeUrlHttpFilter() {
|
||||
Filter filter =
|
||||
buildHttpConnectionManager(
|
||||
"envoy.http_connection_manager",
|
||||
HttpFilter.newBuilder().setName("envoy.filters.http.router").build());
|
||||
FilterChain filterChain = buildFilterChain(filter);
|
||||
Listener listener =
|
||||
Listener.newBuilder()
|
||||
.setName("listener1")
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.addFilterChains(filterChain)
|
||||
.build();
|
||||
StructOrError<io.grpc.xds.EnvoyServerProtoData.Listener> struct =
|
||||
ClientXdsClient.parseServerSideListener(listener, null);
|
||||
assertThat(struct.getErrorDetail())
|
||||
.isEqualTo(
|
||||
"http-connection-manager http-filter envoy.filters.http.router should have "
|
||||
+ "typed-config type "
|
||||
+ "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router");
|
||||
}
|
||||
|
||||
static Filter buildHttpConnectionManager(String name, HttpFilter... httpFilters) {
|
||||
private static Filter buildHttpConnectionManagerFilter(HttpFilter... httpFilters) {
|
||||
return Filter.newBuilder()
|
||||
.setName(name)
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(
|
||||
Any.pack(
|
||||
HttpConnectionManager.newBuilder()
|
||||
.setRds(
|
||||
Rds.newBuilder()
|
||||
.setRouteConfigName("route-config.googleapis.com")
|
||||
.setConfigSource(
|
||||
ConfigSource.newBuilder()
|
||||
.setAds(AggregatedConfigSource.getDefaultInstance())))
|
||||
.addAllHttpFilters(Arrays.asList(httpFilters))
|
||||
.build(),
|
||||
"type.googleapis.com"))
|
||||
.build();
|
||||
}
|
||||
|
||||
static FilterChain buildFilterChain(Filter... filters) {
|
||||
return FilterChain.newBuilder()
|
||||
.setFilterChainMatch(
|
||||
FilterChainMatch.newBuilder()
|
||||
.build())
|
||||
.setTransportSocket(TransportSocket.getDefaultInstance())
|
||||
.addAllFilters(Arrays.asList(filters))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import com.google.common.collect.Iterables;
|
|||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.Message;
|
||||
import io.envoyproxy.envoy.config.listener.v3.Listener;
|
||||
import io.envoyproxy.envoy.config.route.v3.FilterConfig;
|
||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.SdsSecretConfig;
|
||||
import io.grpc.BindableService;
|
||||
|
|
@ -61,6 +60,7 @@ import io.grpc.xds.Endpoints.DropOverload;
|
|||
import io.grpc.xds.Endpoints.LbEndpoint;
|
||||
import io.grpc.xds.Endpoints.LocalityLbEndpoints;
|
||||
import io.grpc.xds.EnvoyProtoData.Node;
|
||||
import io.grpc.xds.EnvoyServerProtoData.FilterChain;
|
||||
import io.grpc.xds.FaultConfig.FractionalPercent.DenominatorType;
|
||||
import io.grpc.xds.LoadStatsManager2.ClusterDropStats;
|
||||
import io.grpc.xds.XdsClient.CdsResourceWatcher;
|
||||
|
|
@ -182,9 +182,10 @@ public abstract class ClientXdsClientTestBase {
|
|||
|
||||
private static final int VHOST_SIZE = 2;
|
||||
// LDS test resources.
|
||||
private final Any testListenerVhosts = Any.pack(mf.buildListener(LDS_RESOURCE,
|
||||
private final Any testListenerVhosts = Any.pack(mf.buildListenerWithApiListener(LDS_RESOURCE,
|
||||
mf.buildRouteConfiguration("do not care", mf.buildOpaqueVirtualHosts(VHOST_SIZE))));
|
||||
private final Any testListenerRds = Any.pack(mf.buildListenerForRds(LDS_RESOURCE, RDS_RESOURCE));
|
||||
private final Any testListenerRds =
|
||||
Any.pack(mf.buildListenerWithApiListenerForRds(LDS_RESOURCE, RDS_RESOURCE));
|
||||
|
||||
// RDS test resources.
|
||||
private final Any testRouteConfig =
|
||||
|
|
@ -420,7 +421,7 @@ public abstract class ClientXdsClientTestBase {
|
|||
public void ldsResourceNotFound() {
|
||||
DiscoveryRpcCall call = startResourceWatcher(LDS, LDS_RESOURCE, ldsResourceWatcher);
|
||||
|
||||
Any listener = Any.pack(mf.buildListener("bar.googleapis.com",
|
||||
Any listener = Any.pack(mf.buildListenerWithApiListener("bar.googleapis.com",
|
||||
mf.buildRouteConfiguration("route-bar.googleapis.com", mf.buildOpaqueVirtualHosts(1))));
|
||||
call.sendResponse(LDS, listener, VERSION_1, "0000");
|
||||
|
||||
|
|
@ -494,9 +495,9 @@ public abstract class ClientXdsClientTestBase {
|
|||
|
||||
// LDS -> {A, B, C}, version 1
|
||||
ImmutableMap<String, Any> resourcesV1 = ImmutableMap.of(
|
||||
"A", Any.pack(mf.buildListenerForRds("A", "A.1")),
|
||||
"B", Any.pack(mf.buildListenerForRds("B", "B.1")),
|
||||
"C", Any.pack(mf.buildListenerForRds("C", "C.1")));
|
||||
"A", Any.pack(mf.buildListenerWithApiListenerForRds("A", "A.1")),
|
||||
"B", Any.pack(mf.buildListenerWithApiListenerForRds("B", "B.1")),
|
||||
"C", Any.pack(mf.buildListenerWithApiListenerForRds("C", "C.1")));
|
||||
call.sendResponse(LDS, resourcesV1.values().asList(), VERSION_1, "0000");
|
||||
// {A, B, C} -> ACK, version 1
|
||||
verifyResourceMetadataAcked(LDS, "A", resourcesV1.get("A"), VERSION_1, TIME_INCREMENT);
|
||||
|
|
@ -507,8 +508,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
// LDS -> {A, B}, version 2
|
||||
// Failed to parse endpoint B
|
||||
ImmutableMap<String, Any> resourcesV2 = ImmutableMap.of(
|
||||
"A", Any.pack(mf.buildListenerForRds("A", "A.2")),
|
||||
"B", Any.pack(mf.buildListenerInvalid("B")));
|
||||
"A", Any.pack(mf.buildListenerWithApiListenerForRds("A", "A.2")),
|
||||
"B", Any.pack(mf.buildListenerWithApiListenerInvalid("B")));
|
||||
call.sendResponse(LDS, resourcesV2.values().asList(), VERSION_2, "0001");
|
||||
// {A, B} -> NACK, version 1, rejected version 2, rejected reason: Failed to parse B
|
||||
// {C} -> ACK, version 1
|
||||
|
|
@ -522,8 +523,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
|
||||
// LDS -> {B, C} version 3
|
||||
ImmutableMap<String, Any> resourcesV3 = ImmutableMap.of(
|
||||
"B", Any.pack(mf.buildListenerForRds("B", "B.3")),
|
||||
"C", Any.pack(mf.buildListenerForRds("C", "C.3")));
|
||||
"B", Any.pack(mf.buildListenerWithApiListenerForRds("B", "B.3")),
|
||||
"C", Any.pack(mf.buildListenerWithApiListenerForRds("C", "C.3")));
|
||||
call.sendResponse(LDS, resourcesV3.values().asList(), VERSION_3, "0002");
|
||||
// {A} -> NACK, version 1, rejected version 2, rejected reason: Failed to parse B
|
||||
// {B, C} -> ACK, version 3
|
||||
|
|
@ -542,7 +543,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
||||
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
||||
.hasSize(VHOST_SIZE);
|
||||
assertThat(fakeClock.getPendingTasks(LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
||||
|
|
@ -556,7 +558,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
// Client sends an ACK LDS request.
|
||||
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().rdsName).isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
||||
.isEqualTo(RDS_RESOURCE);
|
||||
assertThat(fakeClock.getPendingTasks(LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
||||
|
|
@ -573,7 +576,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
LdsResourceWatcher watcher = mock(LdsResourceWatcher.class);
|
||||
xdsClient.watchLdsResource(LDS_RESOURCE, watcher);
|
||||
verify(watcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().rdsName).isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
||||
.isEqualTo(RDS_RESOURCE);
|
||||
call.verifyNoMoreRequest();
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
||||
|
|
@ -602,14 +606,16 @@ public abstract class ClientXdsClientTestBase {
|
|||
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
||||
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
||||
.hasSize(VHOST_SIZE);
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
||||
|
||||
// Updated LDS response.
|
||||
call.sendResponse(LDS, testListenerRds, VERSION_2, "0001");
|
||||
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_2, "0001", NODE);
|
||||
verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().rdsName).isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
||||
.isEqualTo(RDS_RESOURCE);
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_2, TIME_INCREMENT * 2);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
||||
}
|
||||
|
|
@ -619,7 +625,7 @@ public abstract class ClientXdsClientTestBase {
|
|||
Assume.assumeTrue(useProtocolV3());
|
||||
DiscoveryRpcCall call = startResourceWatcher(LDS, LDS_RESOURCE, ldsResourceWatcher);
|
||||
Any listener = Any.pack(
|
||||
mf.buildListener(
|
||||
mf.buildListenerWithApiListener(
|
||||
LDS_RESOURCE,
|
||||
mf.buildRouteConfiguration(
|
||||
"do not care",
|
||||
|
|
@ -657,9 +663,10 @@ public abstract class ClientXdsClientTestBase {
|
|||
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
||||
|
||||
LdsUpdate ldsUpdate = ldsUpdateCaptor.getValue();
|
||||
assertThat(ldsUpdate.virtualHosts).hasSize(2);
|
||||
assertThat(ldsUpdate.filterChain.get(0).name).isEqualTo("envoy.fault");
|
||||
FaultConfig faultConfig = (FaultConfig) ldsUpdate.virtualHosts.get(0)
|
||||
assertThat(ldsUpdate.httpConnectionManager().virtualHosts()).hasSize(2);
|
||||
assertThat(ldsUpdate.httpConnectionManager().httpFilterConfigs().get(0).name)
|
||||
.isEqualTo("envoy.fault");
|
||||
FaultConfig faultConfig = (FaultConfig) ldsUpdate.httpConnectionManager().virtualHosts().get(0)
|
||||
.filterConfigOverrides().get("envoy.fault");
|
||||
assertThat(faultConfig.faultDelay().delayNanos()).isEqualTo(300);
|
||||
assertThat(faultConfig.faultDelay().percent().numerator()).isEqualTo(1000);
|
||||
|
|
@ -667,7 +674,7 @@ public abstract class ClientXdsClientTestBase {
|
|||
.isEqualTo(DenominatorType.MILLION);
|
||||
assertThat(faultConfig.faultAbort()).isNull();
|
||||
assertThat(faultConfig.maxActiveFaults()).isEqualTo(100);
|
||||
faultConfig = (FaultConfig) ldsUpdate.virtualHosts.get(1)
|
||||
faultConfig = (FaultConfig) ldsUpdate.httpConnectionManager().virtualHosts().get(1)
|
||||
.filterConfigOverrides().get("envoy.fault");
|
||||
assertThat(faultConfig.faultDelay()).isNull();
|
||||
assertThat(faultConfig.faultAbort().status().getCode()).isEqualTo(Status.Code.UNAVAILABLE);
|
||||
|
|
@ -686,7 +693,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
call.sendResponse(LDS, testListenerVhosts, VERSION_1, "0000");
|
||||
call.verifyRequest(LDS, LDS_RESOURCE, VERSION_1, "0000", NODE);
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
||||
.hasSize(VHOST_SIZE);
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 0, 0);
|
||||
|
||||
|
|
@ -721,19 +729,22 @@ public abstract class ClientXdsClientTestBase {
|
|||
verifyResourceMetadataDoesNotExist(LDS, ldsResourceTwo);
|
||||
verifySubscribedResourcesMetadataSizes(2, 0, 0, 0);
|
||||
|
||||
Any listenerTwo = Any.pack(mf.buildListenerForRds(ldsResourceTwo, RDS_RESOURCE));
|
||||
Any listenerTwo = Any.pack(mf.buildListenerWithApiListenerForRds(ldsResourceTwo, RDS_RESOURCE));
|
||||
call.sendResponse(LDS, ImmutableList.of(testListenerVhosts, listenerTwo), VERSION_1, "0000");
|
||||
// ldsResourceWatcher called with listenerVhosts.
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
||||
.hasSize(VHOST_SIZE);
|
||||
// watcher1 called with listenerTwo.
|
||||
verify(watcher1).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().rdsName).isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).isNull();
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
||||
.isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts()).isNull();
|
||||
// watcher2 called with listenerTwo.
|
||||
verify(watcher2).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().rdsName).isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).isNull();
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
||||
.isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts()).isNull();
|
||||
// Metadata of both listeners is stored.
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerVhosts, VERSION_1, TIME_INCREMENT);
|
||||
verifyResourceMetadataAcked(LDS, ldsResourceTwo, listenerTwo, VERSION_1, TIME_INCREMENT);
|
||||
|
|
@ -933,7 +944,7 @@ public abstract class ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void rdsResourceDeletedByLds() {
|
||||
public void rdsResourceDeletedByLdsApiListener() {
|
||||
xdsClient.watchLdsResource(LDS_RESOURCE, ldsResourceWatcher);
|
||||
xdsClient.watchRdsResource(RDS_RESOURCE, rdsResourceWatcher);
|
||||
verifyResourceMetadataRequested(LDS, LDS_RESOURCE);
|
||||
|
|
@ -943,7 +954,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
DiscoveryRpcCall call = resourceDiscoveryCalls.poll();
|
||||
call.sendResponse(LDS, testListenerRds, VERSION_1, "0000");
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().rdsName).isEqualTo(RDS_RESOURCE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().rdsName())
|
||||
.isEqualTo(RDS_RESOURCE);
|
||||
verifyResourceMetadataAcked(LDS, LDS_RESOURCE, testListenerRds, VERSION_1, TIME_INCREMENT);
|
||||
verifyResourceMetadataRequested(RDS, RDS_RESOURCE);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
||||
|
|
@ -957,7 +969,8 @@ public abstract class ClientXdsClientTestBase {
|
|||
|
||||
call.sendResponse(LDS, testListenerVhosts, VERSION_2, "0001");
|
||||
verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
||||
assertThat(ldsUpdateCaptor.getValue().httpConnectionManager().virtualHosts())
|
||||
.hasSize(VHOST_SIZE);
|
||||
verify(rdsResourceWatcher).onResourceDoesNotExist(RDS_RESOURCE);
|
||||
verifyResourceMetadataDoesNotExist(RDS, RDS_RESOURCE);
|
||||
verifyResourceMetadataAcked(
|
||||
|
|
@ -965,6 +978,68 @@ public abstract class ClientXdsClientTestBase {
|
|||
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rdsResourcesDeletedByLdsTcpListener() {
|
||||
Assume.assumeTrue(useProtocolV3());
|
||||
xdsClient.watchLdsResource(LISTENER_RESOURCE, ldsResourceWatcher);
|
||||
xdsClient.watchRdsResource(RDS_RESOURCE, rdsResourceWatcher);
|
||||
verifyResourceMetadataRequested(LDS, LISTENER_RESOURCE);
|
||||
verifyResourceMetadataRequested(RDS, RDS_RESOURCE);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
||||
|
||||
Message hcmFilter = mf.buildHttpConnectionManagerFilter(
|
||||
RDS_RESOURCE, null, Collections.<Message>emptyList());
|
||||
Message downstreamTlsContext = CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"google-sds-config-default", "ROOTCA");
|
||||
Message filterChain = mf.buildFilterChain(
|
||||
Collections.<String>emptyList(), downstreamTlsContext, hcmFilter);
|
||||
Any packedListener =
|
||||
Any.pack(mf.buildListenerWithFilterChain(LISTENER_RESOURCE, 7000, "0.0.0.0", filterChain));
|
||||
|
||||
// Simulates receiving the requested LDS resource as a TCP listener with a filter chain
|
||||
// referencing RDS_RESOURCE.
|
||||
DiscoveryRpcCall call = resourceDiscoveryCalls.poll();
|
||||
call.sendResponse(LDS, packedListener, VERSION_1, "0000");
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
|
||||
assertThat(ldsUpdateCaptor.getValue().listener().getFilterChains()).hasSize(1);
|
||||
FilterChain parsedFilterChain = Iterables.getOnlyElement(
|
||||
ldsUpdateCaptor.getValue().listener().getFilterChains());
|
||||
assertThat(parsedFilterChain.getHttpConnectionManager().rdsName()).isEqualTo(RDS_RESOURCE);
|
||||
verifyResourceMetadataAcked(LDS, LISTENER_RESOURCE, packedListener, VERSION_1, TIME_INCREMENT);
|
||||
verifyResourceMetadataRequested(RDS, RDS_RESOURCE);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
||||
|
||||
// Simulates receiving the requested RDS resource.
|
||||
call.sendResponse(RDS, testRouteConfig, VERSION_1, "0000");
|
||||
verify(rdsResourceWatcher).onChanged(rdsUpdateCaptor.capture());
|
||||
assertThat(rdsUpdateCaptor.getValue().virtualHosts).hasSize(VHOST_SIZE);
|
||||
verifyResourceMetadataAcked(RDS, RDS_RESOURCE, testRouteConfig, VERSION_1, TIME_INCREMENT * 2);
|
||||
|
||||
// Simulates receiving an updated version of the requested LDS resource as a TCP listener
|
||||
// with a filter chain containing inlined RouteConfiguration.
|
||||
hcmFilter = mf.buildHttpConnectionManagerFilter(
|
||||
null,
|
||||
mf.buildRouteConfiguration(
|
||||
"route-bar.googleapis.com", mf.buildOpaqueVirtualHosts(VHOST_SIZE)),
|
||||
Collections.<Message>emptyList());
|
||||
filterChain = mf.buildFilterChain(
|
||||
Collections.<String>emptyList(), downstreamTlsContext, hcmFilter);
|
||||
packedListener =
|
||||
Any.pack(mf.buildListenerWithFilterChain(LISTENER_RESOURCE, 7000, "0.0.0.0", filterChain));
|
||||
call.sendResponse(LDS, packedListener, VERSION_2, "0001");
|
||||
verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().listener().getFilterChains()).hasSize(1);
|
||||
parsedFilterChain = Iterables.getOnlyElement(
|
||||
ldsUpdateCaptor.getValue().listener().getFilterChains());
|
||||
assertThat(parsedFilterChain.getHttpConnectionManager().virtualHosts()).hasSize(VHOST_SIZE);
|
||||
verify(rdsResourceWatcher).onResourceDoesNotExist(RDS_RESOURCE);
|
||||
verifyResourceMetadataDoesNotExist(RDS, RDS_RESOURCE);
|
||||
verifyResourceMetadataAcked(
|
||||
LDS, LISTENER_RESOURCE, packedListener, VERSION_2, TIME_INCREMENT * 3);
|
||||
verifySubscribedResourcesMetadataSizes(1, 0, 1, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multipleRdsWatchers() {
|
||||
String rdsResourceTwo = "route-bar.googleapis.com";
|
||||
|
|
@ -1873,7 +1948,7 @@ public abstract class ClientXdsClientTestBase {
|
|||
call.verifyRequest(EDS, EDS_RESOURCE, "", "", NODE);
|
||||
|
||||
List<Any> listeners = ImmutableList.of(
|
||||
Any.pack(mf.buildListener(LDS_RESOURCE,
|
||||
Any.pack(mf.buildListenerWithApiListener(LDS_RESOURCE,
|
||||
mf.buildRouteConfiguration("do not care", mf.buildOpaqueVirtualHosts(2)))));
|
||||
call.sendResponse(LDS, listeners, "63", "3242");
|
||||
call.verifyRequest(LDS, LDS_RESOURCE, "63", "3242", NODE);
|
||||
|
|
@ -2018,36 +2093,34 @@ public abstract class ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void serverSideListenerFound() throws InvalidProtocolBufferException {
|
||||
public void serverSideListenerFound() {
|
||||
Assume.assumeTrue(useProtocolV3());
|
||||
ClientXdsClientTestBase.DiscoveryRpcCall call =
|
||||
startResourceWatcher(LDS, LISTENER_RESOURCE, ldsResourceWatcher);
|
||||
Message hcmFilter = mf.buildHttpConnectionManagerFilter(
|
||||
"route-foo.googleapis.com", null, Collections.<Message>emptyList());
|
||||
Message downstreamTlsContext = CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"google-sds-config-default", "ROOTCA");
|
||||
Message filterChain = mf.buildFilterChain(
|
||||
Collections.<String>emptyList(), downstreamTlsContext, hcmFilter);
|
||||
Message listener =
|
||||
mf.buildListenerWithFilterChain(
|
||||
LISTENER_RESOURCE, 7000, "0.0.0.0", "google-sds-config-default", "ROOTCA");
|
||||
mf.buildListenerWithFilterChain(LISTENER_RESOURCE, 7000, "0.0.0.0", filterChain);
|
||||
List<Any> listeners = ImmutableList.of(Any.pack(listener));
|
||||
call.sendResponse(ResourceType.LDS, listeners, "0", "0000");
|
||||
// Client sends an ACK LDS request.
|
||||
call.verifyRequest(
|
||||
ResourceType.LDS, Collections.singletonList(LISTENER_RESOURCE), "0", "0000", NODE);
|
||||
verify(ldsResourceWatcher).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().listener)
|
||||
.isEqualTo(EnvoyServerProtoData.Listener
|
||||
.fromEnvoyProtoListener((Listener) listener, tlsContextManager));
|
||||
|
||||
listener =
|
||||
mf.buildListenerWithFilterChain(
|
||||
LISTENER_RESOURCE, 7000, "0.0.0.0", "CERT2", "ROOTCA2");
|
||||
listeners = ImmutableList.of(Any.pack(listener));
|
||||
call.sendResponse(ResourceType.LDS, listeners, "1", "0001");
|
||||
|
||||
// Client sends an ACK LDS request.
|
||||
call.verifyRequest(
|
||||
ResourceType.LDS, Collections.singletonList(LISTENER_RESOURCE), "1", "0001", NODE);
|
||||
verify(ldsResourceWatcher, times(2)).onChanged(ldsUpdateCaptor.capture());
|
||||
assertThat(ldsUpdateCaptor.getValue().listener)
|
||||
.isEqualTo(EnvoyServerProtoData.Listener
|
||||
.fromEnvoyProtoListener((Listener) listener, tlsContextManager));
|
||||
EnvoyServerProtoData.Listener parsedListener = ldsUpdateCaptor.getValue().listener();
|
||||
assertThat(parsedListener.getName()).isEqualTo(LISTENER_RESOURCE);
|
||||
assertThat(parsedListener.getAddress()).isEqualTo("0.0.0.0:7000");
|
||||
assertThat(parsedListener.getDefaultFilterChain()).isNull();
|
||||
assertThat(parsedListener.getFilterChains()).hasSize(1);
|
||||
FilterChain parsedFilterChain = Iterables.getOnlyElement(parsedListener.getFilterChains());
|
||||
assertThat(parsedFilterChain.getFilterChainMatch().getApplicationProtocols()).isEmpty();
|
||||
assertThat(parsedFilterChain.getHttpConnectionManager().rdsName())
|
||||
.isEqualTo("route-foo.googleapis.com");
|
||||
assertThat(parsedFilterChain.getHttpConnectionManager().httpFilterConfigs()).isEmpty();
|
||||
|
||||
assertThat(fakeClock.getPendingTasks(LDS_RESOURCE_FETCH_TIMEOUT_TASK_FILTER)).isEmpty();
|
||||
}
|
||||
|
|
@ -2057,18 +2130,14 @@ public abstract class ClientXdsClientTestBase {
|
|||
Assume.assumeTrue(useProtocolV3());
|
||||
ClientXdsClientTestBase.DiscoveryRpcCall call =
|
||||
startResourceWatcher(LDS, LISTENER_RESOURCE, ldsResourceWatcher);
|
||||
final Message filterChainInbound =
|
||||
mf.buildFilterChain(
|
||||
Arrays.asList("managed-mtls"),
|
||||
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"google-sds-config-default", "ROOTCA"),
|
||||
mf.buildTestFilter("envoy.http_connection_manager"));
|
||||
Message listener =
|
||||
mf.buildListenerWithFilterChain(
|
||||
"grpc/server?xds.resource.listening_address=0.0.0.0:8000",
|
||||
7000,
|
||||
"0.0.0.0",
|
||||
filterChainInbound);
|
||||
Message hcmFilter = mf.buildHttpConnectionManagerFilter(
|
||||
"route-foo.googleapis.com", null, Collections.<Message>emptyList());
|
||||
Message downstreamTlsContext = CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"google-sds-config-default", "ROOTCA");
|
||||
Message filterChain = mf.buildFilterChain(
|
||||
Collections.singletonList("managed-mtls"), downstreamTlsContext, hcmFilter);
|
||||
Message listener = mf.buildListenerWithFilterChain(
|
||||
"grpc/server?xds.resource.listening_address=0.0.0.0:8000", 7000, "0.0.0.0", filterChain);
|
||||
List<Any> listeners = ImmutableList.of(Any.pack(listener));
|
||||
call.sendResponse(ResourceType.LDS, listeners, "0", "0000");
|
||||
// Client sends an ACK LDS request.
|
||||
|
|
@ -2162,16 +2231,18 @@ public abstract class ClientXdsClientTestBase {
|
|||
/** Throws {@link InvalidProtocolBufferException} on {@link Any#unpack(Class)}. */
|
||||
protected static final Any FAILING_ANY = Any.newBuilder().setTypeUrl("fake").build();
|
||||
|
||||
protected final Message buildListener(String name, Message routeConfiguration) {
|
||||
return buildListener(name, routeConfiguration, Collections.<Message>emptyList());
|
||||
protected final Message buildListenerWithApiListener(String name, Message routeConfiguration) {
|
||||
return buildListenerWithApiListener(
|
||||
name, routeConfiguration, Collections.<Message>emptyList());
|
||||
}
|
||||
|
||||
protected abstract Message buildListener(
|
||||
protected abstract Message buildListenerWithApiListener(
|
||||
String name, Message routeConfiguration, List<? extends Message> httpFilters);
|
||||
|
||||
protected abstract Message buildListenerForRds(String name, String rdsResourceName);
|
||||
protected abstract Message buildListenerWithApiListenerForRds(
|
||||
String name, String rdsResourceName);
|
||||
|
||||
protected abstract Message buildListenerInvalid(String name);
|
||||
protected abstract Message buildListenerWithApiListenerInvalid(String name);
|
||||
|
||||
protected abstract Message buildHttpFilter(
|
||||
String name, @Nullable Any typedConfig, boolean isOptional);
|
||||
|
|
@ -2239,9 +2310,7 @@ public abstract class ClientXdsClientTestBase {
|
|||
protected abstract Message buildListenerWithFilterChain(
|
||||
String name, int portValue, String address, Message... filterChains);
|
||||
|
||||
protected abstract Message buildListenerWithFilterChain(
|
||||
String name, int portValue, String address, String certName, String validationContextName);
|
||||
|
||||
protected abstract Message buildTestFilter(String name);
|
||||
protected abstract Message buildHttpConnectionManagerFilter(
|
||||
@Nullable String rdsName, @Nullable Message routeConfig, List<Message> httpFilters);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@ public class ClientXdsClientV2Test extends ClientXdsClientTestBase {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Message buildListener(
|
||||
protected Message buildListenerWithApiListener(
|
||||
String name, Message routeConfiguration, List<? extends Message> httpFilters) {
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
|
|
@ -270,7 +270,7 @@ public class ClientXdsClientV2Test extends ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message buildListenerForRds(String name, String rdsResourceName) {
|
||||
protected Message buildListenerWithApiListenerForRds(String name, String rdsResourceName) {
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
.setAddress(Address.getDefaultInstance())
|
||||
|
|
@ -289,7 +289,7 @@ public class ClientXdsClientV2Test extends ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message buildListenerInvalid(String name) {
|
||||
protected Message buildListenerWithApiListenerInvalid(String name) {
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
.setAddress(Address.getDefaultInstance())
|
||||
|
|
@ -629,13 +629,8 @@ public class ClientXdsClientV2Test extends ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message buildListenerWithFilterChain(
|
||||
String name, int portValue, String address, String certName, String validationContextName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Message buildTestFilter(String name) {
|
||||
protected Message buildHttpConnectionManagerFilter(
|
||||
@Nullable String rdsName, @Nullable Message routeConfig, List<Message> httpFilters) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,7 +98,6 @@ import io.grpc.Context.CancellationListener;
|
|||
import io.grpc.Status;
|
||||
import io.grpc.stub.StreamObserver;
|
||||
import io.grpc.xds.AbstractXdsClient.ResourceType;
|
||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
|
@ -264,7 +263,7 @@ public class ClientXdsClientV3Test extends ClientXdsClientTestBase {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected Message buildListener(
|
||||
protected Message buildListenerWithApiListener(
|
||||
String name, Message routeConfiguration, List<? extends Message> httpFilters) {
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
|
|
@ -280,7 +279,7 @@ public class ClientXdsClientV3Test extends ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message buildListenerForRds(String name, String rdsResourceName) {
|
||||
protected Message buildListenerWithApiListenerForRds(String name, String rdsResourceName) {
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
.setAddress(Address.getDefaultInstance())
|
||||
|
|
@ -299,7 +298,7 @@ public class ClientXdsClientV3Test extends ClientXdsClientTestBase {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Message buildListenerInvalid(String name) {
|
||||
protected Message buildListenerWithApiListenerInvalid(String name) {
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
.setAddress(Address.getDefaultInstance())
|
||||
|
|
@ -700,40 +699,33 @@ public class ClientXdsClientV3Test extends ClientXdsClientTestBase {
|
|||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
.setAddress(listenerAddress)
|
||||
.setDefaultFilterChain(FilterChain.getDefaultInstance())
|
||||
.addAllFilterChains(Arrays.asList(filterChainsArray))
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Listener buildListenerWithFilterChain(
|
||||
String name, int portValue, String address, String certName, String validationContextName) {
|
||||
FilterChain filterChain =
|
||||
buildFilterChain(
|
||||
Arrays.<String>asList(),
|
||||
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
certName, validationContextName),
|
||||
buildTestFilter("envoy.http_connection_manager"));
|
||||
io.envoyproxy.envoy.config.core.v3.Address listenerAddress =
|
||||
io.envoyproxy.envoy.config.core.v3.Address.newBuilder()
|
||||
.setSocketAddress(
|
||||
SocketAddress.newBuilder().setPortValue(portValue).setAddress(address))
|
||||
.build();
|
||||
return Listener.newBuilder()
|
||||
.setName(name)
|
||||
.setAddress(listenerAddress)
|
||||
.setDefaultFilterChain(FilterChain.getDefaultInstance())
|
||||
.addAllFilterChains(Arrays.asList(filterChain))
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Filter buildTestFilter(String name) {
|
||||
protected Message buildHttpConnectionManagerFilter(
|
||||
@Nullable String rdsName, @Nullable Message routeConfig, List<Message> httpFilters) {
|
||||
HttpConnectionManager.Builder hcmBuilder = HttpConnectionManager.newBuilder();
|
||||
if (rdsName != null) {
|
||||
hcmBuilder.setRds(
|
||||
Rds.newBuilder()
|
||||
.setRouteConfigName(rdsName)
|
||||
.setConfigSource(
|
||||
ConfigSource.newBuilder()
|
||||
.setAds(AggregatedConfigSource.getDefaultInstance())));
|
||||
}
|
||||
if (routeConfig != null) {
|
||||
hcmBuilder.setRouteConfig((RouteConfiguration) routeConfig);
|
||||
}
|
||||
for (Message httpFilter : httpFilters) {
|
||||
hcmBuilder.addHttpFilters((HttpFilter) httpFilter);
|
||||
}
|
||||
return Filter.newBuilder()
|
||||
.setName(name)
|
||||
.setTypedConfig(Any.pack(HttpConnectionManager.getDefaultInstance()))
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(
|
||||
Any.pack(hcmBuilder.build(), "type.googleapis.com"))
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ import io.grpc.LoadBalancer.Helper;
|
|||
import io.grpc.LoadBalancerProvider;
|
||||
import io.grpc.LoadBalancerRegistry;
|
||||
import io.grpc.NameResolver.ConfigOrError;
|
||||
import io.grpc.Status;
|
||||
import io.grpc.Status.Code;
|
||||
import io.grpc.internal.JsonParser;
|
||||
import io.grpc.internal.ServiceConfigUtil.PolicySelection;
|
||||
import io.grpc.xds.ClusterManagerLoadBalancerProvider.ClusterManagerConfig;
|
||||
|
|
@ -36,11 +38,12 @@ import org.junit.runners.JUnit4;
|
|||
@RunWith(JUnit4.class)
|
||||
public class ClusterManagerLoadBalancerProviderTest {
|
||||
|
||||
private final LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry();
|
||||
private final ClusterManagerLoadBalancerProvider provider =
|
||||
new ClusterManagerLoadBalancerProvider(lbRegistry);
|
||||
|
||||
@Test
|
||||
public void parseClusterManagerLoadBalancingPolicyConfig() throws IOException {
|
||||
LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry();
|
||||
ClusterManagerLoadBalancerProvider provider =
|
||||
new ClusterManagerLoadBalancerProvider(lbRegistry);
|
||||
public void parseLoadBalancingConfig_valid() throws IOException {
|
||||
final Object fooConfig = new Object();
|
||||
LoadBalancerProvider lbProviderFoo = new LoadBalancerProvider() {
|
||||
@Override
|
||||
|
|
@ -136,6 +139,20 @@ public class ClusterManagerLoadBalancerProviderTest {
|
|||
new PolicySelection(lbProviderBar, barConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseLoadBalancingPolicyConfig_emptyChildPolicy() throws IOException {
|
||||
String clusterManagerConfigJson = "{\n"
|
||||
+ " \"childPolicy\": {}\n"
|
||||
+ "}";
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, ?> rawLbConfigMap = (Map<String, ?>) JsonParser.parse(clusterManagerConfigJson);
|
||||
ConfigOrError configOrError = provider.parseLoadBalancingPolicyConfig(rawLbConfigMap);
|
||||
Status error = configOrError.getError();
|
||||
assertThat(error.getCode()).isEqualTo(Code.INTERNAL);
|
||||
assertThat(error.getDescription())
|
||||
.startsWith("No child policy provided for cluster_manager LB policy");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registered() {
|
||||
LoadBalancerProvider provider =
|
||||
|
|
|
|||
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 The gRPC Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.grpc.xds;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.UInt32Value;
|
||||
import io.envoyproxy.envoy.config.core.v3.Address;
|
||||
import io.envoyproxy.envoy.config.core.v3.CidrRange;
|
||||
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
|
||||
import io.envoyproxy.envoy.config.core.v3.TrafficDirection;
|
||||
import io.envoyproxy.envoy.config.core.v3.TransportSocket;
|
||||
import io.envoyproxy.envoy.config.listener.v3.Filter;
|
||||
import io.envoyproxy.envoy.config.listener.v3.FilterChain;
|
||||
import io.envoyproxy.envoy.config.listener.v3.FilterChainMatch;
|
||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
|
||||
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.SdsSecretConfig;
|
||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||
import io.grpc.xds.EnvoyServerProtoData.Listener;
|
||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||
import io.grpc.xds.internal.sds.SslContextProviderSupplier;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EnvoyServerProtoData}.
|
||||
*/
|
||||
@RunWith(JUnit4.class)
|
||||
public class EnvoyServerProtoDataTest {
|
||||
|
||||
@Test
|
||||
public void listener_convertFromListenerProto() throws InvalidProtocolBufferException {
|
||||
Address address =
|
||||
Address.newBuilder()
|
||||
.setSocketAddress(
|
||||
SocketAddress.newBuilder().setPortValue(8000).setAddress("10.2.1.34").build())
|
||||
.build();
|
||||
io.envoyproxy.envoy.config.listener.v3.Listener listener =
|
||||
io.envoyproxy.envoy.config.listener.v3.Listener.newBuilder()
|
||||
.setName("8000")
|
||||
.setAddress(address)
|
||||
.addFilterChains(createInFilter())
|
||||
.setDefaultFilterChain(createDefaultFilterChain())
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.build();
|
||||
|
||||
Listener xdsListener = Listener.fromEnvoyProtoListener(listener, mock(TlsContextManager.class));
|
||||
assertThat(xdsListener.getName()).isEqualTo("8000");
|
||||
assertThat(xdsListener.getAddress()).isEqualTo("10.2.1.34:8000");
|
||||
List<EnvoyServerProtoData.FilterChain> filterChains = xdsListener.getFilterChains();
|
||||
assertThat(filterChains).isNotNull();
|
||||
assertThat(filterChains.size()).isEqualTo(1);
|
||||
|
||||
EnvoyServerProtoData.FilterChain inFilter = filterChains.get(0);
|
||||
assertThat(inFilter).isNotNull();
|
||||
EnvoyServerProtoData.FilterChainMatch inFilterChainMatch = inFilter.getFilterChainMatch();
|
||||
assertThat(inFilterChainMatch).isNotNull();
|
||||
assertThat(inFilterChainMatch.getDestinationPort()).isEqualTo(8000);
|
||||
assertThat(inFilterChainMatch.getApplicationProtocols())
|
||||
.containsExactlyElementsIn(Arrays.asList("managed-mtls", "h2"));
|
||||
assertThat(inFilterChainMatch.getServerNames())
|
||||
.containsExactlyElementsIn(Arrays.asList("server1", "server2"));
|
||||
assertThat(inFilterChainMatch.getTransportProtocol()).isEqualTo("tls");
|
||||
assertThat(inFilterChainMatch.getPrefixRanges())
|
||||
.containsExactly(new EnvoyServerProtoData.CidrRange("10.20.0.15", 32));
|
||||
assertThat(inFilterChainMatch.getSourcePrefixRanges())
|
||||
.containsExactly(new EnvoyServerProtoData.CidrRange("10.30.3.0", 24));
|
||||
assertThat(inFilterChainMatch.getConnectionSourceType())
|
||||
.isEqualTo(EnvoyServerProtoData.ConnectionSourceType.EXTERNAL);
|
||||
assertThat(inFilterChainMatch.getSourcePorts()).containsExactly(200, 300);
|
||||
SslContextProviderSupplier sslContextProviderSupplier = inFilter
|
||||
.getSslContextProviderSupplier();
|
||||
assertThat(sslContextProviderSupplier.getTlsContext()).isInstanceOf(DownstreamTlsContext.class);
|
||||
DownstreamTlsContext inFilterTlsContext = (DownstreamTlsContext) sslContextProviderSupplier
|
||||
.getTlsContext();
|
||||
assertThat(inFilterTlsContext.getCommonTlsContext()).isNotNull();
|
||||
CommonTlsContext commonTlsContext = inFilterTlsContext.getCommonTlsContext();
|
||||
List<SdsSecretConfig> tlsCertSdsConfigs = commonTlsContext
|
||||
.getTlsCertificateSdsSecretConfigsList();
|
||||
assertThat(tlsCertSdsConfigs).hasSize(1);
|
||||
assertThat(tlsCertSdsConfigs.get(0).getName()).isEqualTo("google-sds-config-default");
|
||||
|
||||
EnvoyServerProtoData.FilterChain defaultFilter = xdsListener.getDefaultFilterChain();
|
||||
assertThat(defaultFilter).isNotNull();
|
||||
EnvoyServerProtoData.FilterChainMatch defaultFilterChainMatch =
|
||||
defaultFilter.getFilterChainMatch();
|
||||
assertThat(defaultFilterChainMatch).isNotNull();
|
||||
assertThat(defaultFilterChainMatch.getDestinationPort()).isEqualTo(8001);
|
||||
assertThat(defaultFilterChainMatch.getPrefixRanges())
|
||||
.containsExactly(new EnvoyServerProtoData.CidrRange("10.20.0.16", 30));
|
||||
}
|
||||
|
||||
private static FilterChain createInFilter() {
|
||||
FilterChain filterChain =
|
||||
FilterChain.newBuilder()
|
||||
.setFilterChainMatch(
|
||||
FilterChainMatch.newBuilder()
|
||||
.setDestinationPort(UInt32Value.of(8000))
|
||||
.addAllServerNames(Arrays.asList("server1", "server2"))
|
||||
.setTransportProtocol("tls")
|
||||
.addAllApplicationProtocols(Arrays.asList("managed-mtls", "h2"))
|
||||
.addPrefixRanges(CidrRange.newBuilder()
|
||||
.setAddressPrefix("10.20.0.15")
|
||||
.setPrefixLen(UInt32Value.of(32))
|
||||
.build())
|
||||
.addSourcePrefixRanges(
|
||||
CidrRange.newBuilder()
|
||||
.setAddressPrefix("10.30.3.0")
|
||||
.setPrefixLen(UInt32Value.of(24))
|
||||
.build())
|
||||
.setSourceType(FilterChainMatch.ConnectionSourceType.EXTERNAL)
|
||||
.addSourcePorts(200)
|
||||
.addSourcePorts(300)
|
||||
.build())
|
||||
.setTransportSocket(TransportSocket.newBuilder().setName("envoy.transport_sockets.tls")
|
||||
.setTypedConfig(
|
||||
Any.pack(CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"google-sds-config-default", "ROOTCA")))
|
||||
.build())
|
||||
.addFilters(Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.newBuilder()
|
||||
.setTypeUrl(
|
||||
"type.googleapis.com/"
|
||||
+ "envoy.extensions.filters.network.http_connection_manager"
|
||||
+ ".v3.HttpConnectionManager"))
|
||||
.build())
|
||||
.build();
|
||||
return filterChain;
|
||||
}
|
||||
|
||||
private static FilterChain createDefaultFilterChain() {
|
||||
FilterChain filterChain =
|
||||
FilterChain.newBuilder()
|
||||
.setFilterChainMatch(
|
||||
FilterChainMatch.newBuilder()
|
||||
.setDestinationPort(UInt32Value.of(8001))
|
||||
.addPrefixRanges(
|
||||
CidrRange.newBuilder()
|
||||
.setAddressPrefix("10.20.0.16")
|
||||
.setPrefixLen(UInt32Value.of(30))
|
||||
.build())
|
||||
.build())
|
||||
.setTransportSocket(
|
||||
TransportSocket.newBuilder()
|
||||
.setName("envoy.transport_sockets.tls")
|
||||
.setTypedConfig(
|
||||
Any.pack(
|
||||
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"google-sds-config-default", "ROOTCA")))
|
||||
.build())
|
||||
.addFilters(
|
||||
Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(
|
||||
Any.newBuilder()
|
||||
.setTypeUrl(
|
||||
"type.googleapis.com/"
|
||||
+ "envoy.extensions.filters.network.http_connection_manager"
|
||||
+ ".v3.HttpConnectionManager"))
|
||||
.build())
|
||||
.build();
|
||||
return filterChain;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort.HeaderAbo
|
|||
import io.envoyproxy.envoy.extensions.filters.http.fault.v3.HTTPFault;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent;
|
||||
import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType;
|
||||
import io.grpc.Status.Code;
|
||||
import io.grpc.internal.GrpcUtil;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
|
@ -59,4 +60,32 @@ public class FaultFilterTest {
|
|||
assertThat(faultAbort.percent().denominatorType())
|
||||
.isEqualTo(FaultConfig.FractionalPercent.DenominatorType.HUNDRED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFaultAbort_withHttpStatus() {
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort proto =
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort.newBuilder()
|
||||
.setPercentage(FractionalPercent.newBuilder()
|
||||
.setNumerator(100).setDenominator(DenominatorType.TEN_THOUSAND))
|
||||
.setHttpStatus(400).build();
|
||||
FaultConfig.FaultAbort res = FaultFilter.parseFaultAbort(proto).config;
|
||||
assertThat(res.percent().numerator()).isEqualTo(100);
|
||||
assertThat(res.percent().denominatorType())
|
||||
.isEqualTo(FaultConfig.FractionalPercent.DenominatorType.TEN_THOUSAND);
|
||||
assertThat(res.status().getCode()).isEqualTo(Code.INTERNAL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parseFaultAbort_withGrpcStatus() {
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort proto =
|
||||
io.envoyproxy.envoy.extensions.filters.http.fault.v3.FaultAbort.newBuilder()
|
||||
.setPercentage(FractionalPercent.newBuilder()
|
||||
.setNumerator(600).setDenominator(DenominatorType.MILLION))
|
||||
.setGrpcStatus(Code.DEADLINE_EXCEEDED.value()).build();
|
||||
FaultConfig.FaultAbort faultAbort = FaultFilter.parseFaultAbort(proto).config;
|
||||
assertThat(faultAbort.percent().numerator()).isEqualTo(600);
|
||||
assertThat(faultAbort.percent().denominatorType())
|
||||
.isEqualTo(FaultConfig.FractionalPercent.DenominatorType.MILLION);
|
||||
assertThat(faultAbort.status().getCode()).isEqualTo(Code.DEADLINE_EXCEEDED);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,18 +21,8 @@ import static org.junit.Assert.fail;
|
|||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.protobuf.Any;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.google.protobuf.UInt32Value;
|
||||
import io.envoyproxy.envoy.config.core.v3.Address;
|
||||
import io.envoyproxy.envoy.config.core.v3.CidrRange;
|
||||
import io.envoyproxy.envoy.config.core.v3.SocketAddress;
|
||||
import io.envoyproxy.envoy.config.core.v3.TrafficDirection;
|
||||
import io.envoyproxy.envoy.config.core.v3.TransportSocket;
|
||||
import io.envoyproxy.envoy.config.listener.v3.Filter;
|
||||
import io.envoyproxy.envoy.config.listener.v3.FilterChain;
|
||||
import io.envoyproxy.envoy.config.listener.v3.FilterChainMatch;
|
||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||
import io.grpc.xds.Filter.NamedFilterConfig;
|
||||
import io.grpc.xds.XdsClient.LdsUpdate;
|
||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||
import io.grpc.xds.internal.sds.SslContextProviderSupplier;
|
||||
import io.netty.channel.Channel;
|
||||
|
|
@ -41,6 +31,7 @@ import java.net.InetAddress;
|
|||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -56,6 +47,9 @@ public class FilterChainMatchTest {
|
|||
private static final int PORT = 7000;
|
||||
private static final String LOCAL_IP = "10.1.2.3"; // dest
|
||||
private static final String REMOTE_IP = "10.4.2.3"; // source
|
||||
private static final HttpConnectionManager HTTP_CONNECTION_MANAGER =
|
||||
HttpConnectionManager.forRdsName(
|
||||
10L, "route-config", Collections.<NamedFilterConfig>emptyList());
|
||||
|
||||
@Mock private Channel channel;
|
||||
@Mock private TlsContextManager tlsContextManager;
|
||||
|
|
@ -77,13 +71,13 @@ public class FilterChainMatchTest {
|
|||
xdsClientWrapperForServerSds.shutdown();
|
||||
}
|
||||
|
||||
private DownstreamTlsContext getDownstreamTlsContext() {
|
||||
private EnvoyServerProtoData.DownstreamTlsContext getDownstreamTlsContext() {
|
||||
SslContextProviderSupplier sslContextProviderSupplier =
|
||||
xdsClientWrapperForServerSds.getSslContextProviderSupplier(channel);
|
||||
if (sslContextProviderSupplier != null) {
|
||||
EnvoyServerProtoData.BaseTlsContext tlsContext = sslContextProviderSupplier.getTlsContext();
|
||||
assertThat(tlsContext).isInstanceOf(DownstreamTlsContext.class);
|
||||
return (DownstreamTlsContext) tlsContext;
|
||||
assertThat(tlsContext).isInstanceOf(EnvoyServerProtoData.DownstreamTlsContext.class);
|
||||
return (EnvoyServerProtoData.DownstreamTlsContext) tlsContext;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -101,15 +95,16 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
DownstreamTlsContext tlsContext =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChain filterChain =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain filterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch, HTTP_CONNECTION_MANAGER, tlsContext,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener("listener1", LOCAL_IP, Arrays.asList(filterChain), null);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContext);
|
||||
}
|
||||
|
||||
|
|
@ -126,43 +121,44 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
DownstreamTlsContext tlsContext =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChain filterChain =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext, tlsContextManager);
|
||||
DownstreamTlsContext defaultTlsContext =
|
||||
EnvoyServerProtoData.FilterChain filterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch, HTTP_CONNECTION_MANAGER, tlsContext,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext defaultTlsContext =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, defaultTlsContext, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener("listener1", LOCAL_IP, Arrays.asList(filterChain),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER, defaultTlsContext,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener = new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChain), defaultFilterChain);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(defaultTlsContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultFilterChain() throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContext =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChain filterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContext, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain filterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", null, HTTP_CONNECTION_MANAGER, tlsContext, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.<EnvoyServerProtoData.FilterChain>asList(), filterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPortFails_returnDefaultFilterChain() throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextWithDestPort =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextWithDestPort =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithDestPort =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -175,26 +171,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainWithDestPort =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchWithDestPort, tlsContextWithDestPort,
|
||||
tlsContextManager);
|
||||
DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchWithDestPort, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextWithDestPort, tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextForDefaultFilterChain, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChainWithDestPort), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPrefixRangeMatch() throws UnknownHostException, InvalidProtocolBufferException {
|
||||
public void destPrefixRangeMatch() throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextMatch =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMatch =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -206,28 +204,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainWithMatch =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMatch, tlsContextMatch,
|
||||
tlsContextManager);
|
||||
DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
EnvoyServerProtoData.FilterChain filterChainWithMatch = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchWithMatch, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMatch, tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextForDefaultFilterChain, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMatch), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMatch);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPrefixRangeMismatch_returnDefaultFilterChain()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextMismatch =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMismatch =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
// 10.2.2.0/24 doesn't match LOCAL_IP
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch =
|
||||
|
|
@ -241,27 +239,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainWithMismatch =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMismatch, tlsContextMismatch,
|
||||
tlsContextManager);
|
||||
DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchWithMismatch, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMismatch, tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextForDefaultFilterChain, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMismatch), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dest0LengthPrefixRange()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContext0Length =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext0Length =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
// 10.2.2.0/24 doesn't match LOCAL_IP
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch0Length =
|
||||
|
|
@ -274,28 +273,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain0Length =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch0Length, tlsContext0Length,
|
||||
tlsContextManager);
|
||||
DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
EnvoyServerProtoData.FilterChain filterChain0Length = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch0Length, HTTP_CONNECTION_MANAGER,
|
||||
tlsContext0Length, tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextForDefaultFilterChain, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChain0Length), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContext0Length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPrefixRange_moreSpecificWins()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextLessSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -308,10 +307,11 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific,
|
||||
tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextLessSpecific, tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContextMoreSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -324,27 +324,29 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchMoreSpecific, tlsContextMoreSpecific,
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatchMoreSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMoreSpecific,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
LOCAL_IP,
|
||||
Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPrefixRange_emptyListLessSpecific()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextLessSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -357,10 +359,11 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific,
|
||||
tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextLessSpecific, tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContextMoreSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -373,27 +376,29 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchMoreSpecific, tlsContextMoreSpecific,
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatchMoreSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMoreSpecific,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
LOCAL_IP,
|
||||
Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPrefixRangeIpv6_moreSpecificWins()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel("FE80:0000:0000:0000:0202:B3FF:FE1E:8329", "2001:DB8::8:800:200C:417A", 15000);
|
||||
DownstreamTlsContext tlsContextLessSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -406,10 +411,11 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific,
|
||||
tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextLessSpecific, tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContextMoreSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -422,27 +428,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainMoreSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchMoreSpecific, tlsContextMoreSpecific,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatchMoreSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMoreSpecific, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
"FE80:0000:0000:0000:0202:B3FF:FE1E:8329",
|
||||
Arrays.asList(filterChainLessSpecific, filterChainMoreSpecific),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecific);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void destPrefixRange_moreSpecificWith2Wins()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextMoreSpecificWith2 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecificWith2 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -458,9 +465,10 @@ public class FilterChainMatchTest {
|
|||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
filterChainMatchMoreSpecificWith2, tlsContextMoreSpecificWith2, tlsContextManager);
|
||||
"filter-chain-foo", filterChainMatchMoreSpecificWith2, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMoreSpecificWith2, tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContextLessSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -473,26 +481,27 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextLessSpecific, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
LOCAL_IP,
|
||||
Arrays.asList(filterChainMoreSpecificWith2, filterChainLessSpecific),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sourceTypeMismatch_returnDefaultFilterChain() throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextMismatch =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMismatch =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMismatch =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -505,26 +514,27 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainWithMismatch =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMismatch, tlsContextMismatch,
|
||||
tlsContextManager);
|
||||
DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchWithMismatch, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMismatch, tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER,tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMismatch), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextForDefaultFilterChain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sourceTypeLocal() throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, LOCAL_IP, 15000);
|
||||
DownstreamTlsContext tlsContextMatch =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMatch =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchWithMatch =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -536,28 +546,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainWithMatch =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchWithMatch, tlsContextMatch,
|
||||
tlsContextManager);
|
||||
DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
EnvoyServerProtoData.FilterChain filterChainWithMatch = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatchWithMatch, HTTP_CONNECTION_MANAGER, tlsContextMatch,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextForDefaultFilterChain =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, HTTP_CONNECTION_MANAGER, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChainWithMatch), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMatch);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sourcePrefixRange_moreSpecificWith2Wins()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextMoreSpecificWith2 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextMoreSpecificWith2 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchMoreSpecificWith2 =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -573,9 +583,10 @@ public class FilterChainMatchTest {
|
|||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainMoreSpecificWith2 =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
filterChainMatchMoreSpecificWith2, tlsContextMoreSpecificWith2, tlsContextManager);
|
||||
"filter-chain-foo", filterChainMatchMoreSpecificWith2, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextMoreSpecificWith2, tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContextLessSpecific =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextLessSpecific =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -588,27 +599,28 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainLessSpecific =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatchLessSpecific, tlsContextLessSpecific,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatchLessSpecific, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextLessSpecific, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
LOCAL_IP,
|
||||
Arrays.asList(filterChainMoreSpecificWith2, filterChainLessSpecific),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextMoreSpecificWith2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sourcePrefixRange_2Matchers_expectException()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContext1 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -622,10 +634,11 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain1 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain filterChain1 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch1, HTTP_CONNECTION_MANAGER, tlsContext1,
|
||||
tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContext2 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext2 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -637,14 +650,15 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain2 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, null);
|
||||
EnvoyServerProtoData.FilterChain filterChain2 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatch2, HTTP_CONNECTION_MANAGER, tlsContext2,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, null);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1", LOCAL_IP, Arrays.asList(filterChain1, filterChain2), defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
try {
|
||||
xdsClientWrapperForServerSds.getSslContextProviderSupplier(channel);
|
||||
|
|
@ -656,9 +670,9 @@ public class FilterChainMatchTest {
|
|||
|
||||
@Test
|
||||
public void sourcePortMatch_exactMatchWinsOverEmptyList()
|
||||
throws UnknownHostException, InvalidProtocolBufferException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContextEmptySourcePorts =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextEmptySourcePorts =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchEmptySourcePorts =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -674,9 +688,10 @@ public class FilterChainMatchTest {
|
|||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainEmptySourcePorts =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
filterChainMatchEmptySourcePorts, tlsContextEmptySourcePorts, tlsContextManager);
|
||||
"filter-chain-foo", filterChainMatchEmptySourcePorts, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextEmptySourcePorts, tlsContextManager);
|
||||
|
||||
DownstreamTlsContext tlsContextSourcePortMatch =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextSourcePortMatch =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatchSourcePortMatch =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
|
|
@ -690,18 +705,19 @@ public class FilterChainMatchTest {
|
|||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChainSourcePortMatch =
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
filterChainMatchSourcePortMatch, tlsContextSourcePortMatch, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
"filter-chain-bar", filterChainMatchSourcePortMatch, HTTP_CONNECTION_MANAGER,
|
||||
tlsContextSourcePortMatch, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
LOCAL_IP,
|
||||
Arrays.asList(filterChainEmptySourcePorts, filterChainSourcePortMatch),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 = getDownstreamTlsContext();
|
||||
assertThat(tlsContext1).isSameInstanceAs(tlsContextSourcePortMatch);
|
||||
}
|
||||
|
||||
|
|
@ -713,19 +729,19 @@ public class FilterChainMatchTest {
|
|||
* source-prefix range. - 5th step: out of 2 one with matching source port gets picked
|
||||
*/
|
||||
@Test
|
||||
public void filterChain_5stepMatch() throws UnknownHostException, InvalidProtocolBufferException {
|
||||
public void filterChain_5stepMatch() throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
DownstreamTlsContext tlsContext1 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "VA1");
|
||||
DownstreamTlsContext tlsContext2 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext2 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "VA2");
|
||||
DownstreamTlsContext tlsContext3 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext3 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT3", "VA3");
|
||||
DownstreamTlsContext tlsContext4 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext4 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT4", "VA4");
|
||||
DownstreamTlsContext tlsContext5 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext5 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT5", "VA5");
|
||||
DownstreamTlsContext tlsContext6 =
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext6 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT6", "VA6");
|
||||
|
||||
// has dest port and specific prefix ranges: gets eliminated in step 1
|
||||
|
|
@ -739,8 +755,9 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain1 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext1, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain filterChain1 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-1", filterChainMatch1, HTTP_CONNECTION_MANAGER, tlsContext1,
|
||||
tlsContextManager);
|
||||
|
||||
// next 5 use prefix range: 4 with prefixLen of 30 and last one with 29
|
||||
|
||||
|
|
@ -755,8 +772,9 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain2 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch2, tlsContext2, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain filterChain2 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-2", filterChainMatch2, HTTP_CONNECTION_MANAGER, tlsContext2,
|
||||
tlsContextManager);
|
||||
|
||||
// has prefix ranges with one not matching and source type local: gets eliminated in step 3
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch3 =
|
||||
|
|
@ -771,8 +789,9 @@ public class FilterChainMatchTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain3 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch3, tlsContext3, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain filterChain3 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-3", filterChainMatch3, HTTP_CONNECTION_MANAGER, tlsContext3,
|
||||
tlsContextManager);
|
||||
|
||||
// has prefix ranges with both matching and source type external but non matching source port:
|
||||
// gets eliminated in step 5
|
||||
|
|
@ -789,7 +808,9 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain4 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch4, tlsContext4, tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-4", filterChainMatch4, HTTP_CONNECTION_MANAGER, tlsContext4,
|
||||
tlsContextManager);
|
||||
|
||||
// has prefix ranges with both matching and source type external and matching source port: this
|
||||
// gets selected
|
||||
|
|
@ -808,7 +829,9 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain5 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch5, tlsContext5, tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-5", filterChainMatch5, HTTP_CONNECTION_MANAGER, tlsContext5,
|
||||
tlsContextManager);
|
||||
|
||||
// has prefix range with prefixLen of 29: gets eliminated in step 2
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch6 =
|
||||
|
|
@ -822,10 +845,12 @@ public class FilterChainMatchTest {
|
|||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain6 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch6, tlsContext6, tlsContextManager);
|
||||
new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-6", filterChainMatch6, HTTP_CONNECTION_MANAGER, tlsContext6,
|
||||
tlsContextManager);
|
||||
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, null, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-7", null, HTTP_CONNECTION_MANAGER, null, tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
"listener1",
|
||||
|
|
@ -833,112 +858,77 @@ public class FilterChainMatchTest {
|
|||
Arrays.asList(
|
||||
filterChain1, filterChain2, filterChain3, filterChain4, filterChain5, filterChain6),
|
||||
defaultFilterChain);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContextPicked = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextPicked = getDownstreamTlsContext();
|
||||
assertThat(tlsContextPicked).isSameInstanceAs(tlsContext5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterChainMatch_unsupportedMatchers()
|
||||
throws InvalidProtocolBufferException, UnknownHostException {
|
||||
throws UnknownHostException {
|
||||
setupChannel(LOCAL_IP, REMOTE_IP, 15000);
|
||||
io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext tlsContext1 =
|
||||
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"CERT1", "ROOTCA");
|
||||
io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext tlsContext2 =
|
||||
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"CERT2", "ROOTCA");
|
||||
io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext tlsContext3 =
|
||||
CommonTlsContextTestsUtil.buildTestDownstreamTlsContext(
|
||||
"CERT3", "ROOTCA");
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext1 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT1", "ROOTCA");
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext2 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT2", "ROOTCA");
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContext3 =
|
||||
CommonTlsContextTestsUtil.buildTestInternalDownstreamTlsContext("CERT3", "ROOTCA");
|
||||
|
||||
FilterChainMatch filterChainMatch1 =
|
||||
FilterChainMatch.newBuilder()
|
||||
.addAllServerNames(Arrays.asList("server1", "server2"))
|
||||
.setTransportProtocol("tls")
|
||||
.addAllApplicationProtocols(Arrays.asList("managed-mtls", "h2"))
|
||||
.addPrefixRanges(CidrRange.newBuilder()
|
||||
.setAddressPrefix("10.1.0.0")
|
||||
.setPrefixLen(UInt32Value.of(16))
|
||||
.build())
|
||||
.build();
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch1 =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
0 /* destinationPort */,
|
||||
Collections.singletonList(
|
||||
new EnvoyServerProtoData.CidrRange("10.1.0.0", 16)) /* prefixRange */,
|
||||
Arrays.asList("managed-mtls", "h2") /* applicationProtocol */,
|
||||
Collections.<EnvoyServerProtoData.CidrRange>emptyList() /* sourcePrefixRanges */,
|
||||
EnvoyServerProtoData.ConnectionSourceType.ANY /* sourceType */,
|
||||
Collections.<Integer>emptyList() /* sourcePorts */,
|
||||
Arrays.asList("server1", "server2") /* serverNames */,
|
||||
"tls" /* transportProtocol */);
|
||||
|
||||
FilterChainMatch filterChainMatch2 =
|
||||
FilterChainMatch.newBuilder()
|
||||
.addPrefixRanges(CidrRange.newBuilder()
|
||||
.setAddressPrefix("10.0.0.0")
|
||||
.setPrefixLen(UInt32Value.of(8))
|
||||
.build())
|
||||
.build();
|
||||
EnvoyServerProtoData.FilterChainMatch filterChainMatch2 =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
0 /* destinationPort */,
|
||||
Collections.singletonList(
|
||||
new EnvoyServerProtoData.CidrRange("10.0.0.0", 8)) /* prefixRange */,
|
||||
Collections.<String>emptyList() /* applicationProtocol */,
|
||||
Collections.<EnvoyServerProtoData.CidrRange>emptyList() /* sourcePrefixRanges */,
|
||||
EnvoyServerProtoData.ConnectionSourceType.ANY /* sourceType */,
|
||||
Collections.<Integer>emptyList() /* sourcePorts */,
|
||||
Collections.<String>emptyList() /* serverNames */,
|
||||
"" /* transportProtocol */);
|
||||
|
||||
FilterChain filterChain1 =
|
||||
FilterChain.newBuilder()
|
||||
.setFilterChainMatch(filterChainMatch1)
|
||||
.setTransportSocket(TransportSocket.newBuilder().setName("envoy.transport_sockets.tls")
|
||||
.setTypedConfig(Any.pack(tlsContext1))
|
||||
.build())
|
||||
.addFilters(Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.newBuilder()
|
||||
.setTypeUrl(
|
||||
"type.googleapis.com/"
|
||||
+ "envoy.extensions.filters.network.http_connection_manager"
|
||||
+ ".v3.HttpConnectionManager"))
|
||||
.build())
|
||||
.build();
|
||||
FilterChain filterChain2 =
|
||||
FilterChain.newBuilder()
|
||||
.setFilterChainMatch(filterChainMatch2)
|
||||
.setTransportSocket(TransportSocket.newBuilder().setName("envoy.transport_sockets.tls")
|
||||
.setTypedConfig(Any.pack(tlsContext2))
|
||||
.build())
|
||||
.addFilters(Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.newBuilder()
|
||||
.setTypeUrl(
|
||||
"type.googleapis.com/"
|
||||
+ "envoy.extensions.filters.network.http_connection_manager"
|
||||
+ ".v3.HttpConnectionManager"))
|
||||
.build())
|
||||
.build();
|
||||
FilterChain defaultFilterChain =
|
||||
FilterChain.newBuilder()
|
||||
.setTransportSocket(TransportSocket.newBuilder().setName("envoy.transport_sockets.tls")
|
||||
.setTypedConfig(Any.pack(tlsContext3))
|
||||
.build())
|
||||
.addFilters(Filter.newBuilder()
|
||||
.setName("envoy.http_connection_manager")
|
||||
.setTypedConfig(Any.newBuilder()
|
||||
.setTypeUrl(
|
||||
"type.googleapis.com/"
|
||||
+ "envoy.extensions.filters.network.http_connection_manager"
|
||||
+ ".v3.HttpConnectionManager"))
|
||||
.build())
|
||||
.build();
|
||||
Address address =
|
||||
Address.newBuilder()
|
||||
.setSocketAddress(
|
||||
SocketAddress.newBuilder().setPortValue(8000).setAddress("10.2.1.34").build())
|
||||
.build();
|
||||
io.envoyproxy.envoy.config.listener.v3.Listener listener =
|
||||
io.envoyproxy.envoy.config.listener.v3.Listener.newBuilder()
|
||||
.setName("8000")
|
||||
.setAddress(address)
|
||||
.addFilterChains(filterChain1)
|
||||
.addFilterChains(filterChain2)
|
||||
.setDefaultFilterChain(defaultFilterChain)
|
||||
.setTrafficDirection(TrafficDirection.INBOUND)
|
||||
.build();
|
||||
EnvoyServerProtoData.FilterChainMatch defaultFilterChainMatch =
|
||||
new EnvoyServerProtoData.FilterChainMatch(
|
||||
0 /* destinationPort */,
|
||||
Collections.<EnvoyServerProtoData.CidrRange>emptyList() /* prefixRange */,
|
||||
Collections.<String>emptyList() /* applicationProtocol */,
|
||||
Collections.<EnvoyServerProtoData.CidrRange>emptyList() /* sourcePrefixRanges */,
|
||||
EnvoyServerProtoData.ConnectionSourceType.ANY /* sourceType */,
|
||||
Collections.<Integer>emptyList() /* sourcePorts */,
|
||||
Collections.<String>emptyList() /* serverNames */,
|
||||
"" /* transportProtocol */);
|
||||
|
||||
EnvoyServerProtoData.Listener xdsListener = EnvoyServerProtoData.Listener
|
||||
.fromEnvoyProtoListener(listener, mock(TlsContextManager.class));
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(xdsListener);
|
||||
EnvoyServerProtoData.FilterChain filterChain1 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch1, HTTP_CONNECTION_MANAGER, tlsContext1,
|
||||
mock(TlsContextManager.class));
|
||||
EnvoyServerProtoData.FilterChain filterChain2 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", filterChainMatch2, HTTP_CONNECTION_MANAGER, tlsContext2,
|
||||
mock(TlsContextManager.class));
|
||||
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-baz", defaultFilterChainMatch, HTTP_CONNECTION_MANAGER, tlsContext3,
|
||||
mock(TlsContextManager.class));
|
||||
|
||||
EnvoyServerProtoData.Listener listener = new EnvoyServerProtoData.Listener(
|
||||
"", "10.2.1.34:8000", Arrays.asList(filterChain1, filterChain2), defaultFilterChain);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContextPicked = getDownstreamTlsContext();
|
||||
EnvoyServerProtoData.DownstreamTlsContext tlsContextPicked = getDownstreamTlsContext();
|
||||
// assert defaultFilterChain match
|
||||
assertThat(tlsContextPicked.getCommonTlsContext().getTlsCertificateSdsSecretConfigsList().get(0)
|
||||
.getName()).isEqualTo("CERT3");
|
||||
assertThat(tlsContextPicked.getCommonTlsContext().getTlsCertificateSdsSecretConfigsList()
|
||||
.get(0).getName()).isEqualTo("CERT3");
|
||||
}
|
||||
|
||||
private void setupChannel(String localIp, String remoteIp, int remotePort)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import io.grpc.Status;
|
|||
import io.grpc.StatusException;
|
||||
import io.grpc.inprocess.InProcessSocketAddress;
|
||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||
import io.grpc.xds.XdsClient.LdsUpdate;
|
||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||
import io.grpc.xds.internal.sds.SslContextProvider;
|
||||
import io.grpc.xds.internal.sds.SslContextProviderSupplier;
|
||||
|
|
@ -131,7 +132,7 @@ public class XdsClientWrapperForServerSdsTestMisc {
|
|||
"10.1.2.3",
|
||||
Collections.<EnvoyServerProtoData.FilterChain>emptyList(),
|
||||
null);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
DownstreamTlsContext tlsContext = getDownstreamTlsContext();
|
||||
assertThat(tlsContext).isNull();
|
||||
|
|
|
|||
|
|
@ -202,11 +202,11 @@ public class XdsNameResolverTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void resolving_ldsResourceUpdateRdsName() {
|
||||
Route route1 = Route.create(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
Route route1 = Route.forAction(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster1, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
Route route2 = Route.create(RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
Route route2 = Route.forAction(RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster2, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(20L)),
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
|
|
@ -260,7 +260,7 @@ public class XdsNameResolverTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void resolving_ldsResourceRevokedAndAddedBack() {
|
||||
Route route = Route.create(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
Route route = Route.forAction(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster1, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
|
|
@ -299,7 +299,7 @@ public class XdsNameResolverTest {
|
|||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void resolving_rdsResourceRevokedAndAddedBack() {
|
||||
Route route = Route.create(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
Route route = Route.forAction(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster1, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
|
|
@ -373,11 +373,11 @@ public class XdsNameResolverTest {
|
|||
}
|
||||
|
||||
private List<VirtualHost> buildUnmatchedVirtualHosts() {
|
||||
Route route1 = Route.create(RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
Route route1 = Route.forAction(RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster2, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
Route route2 = Route.create(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
Route route2 = Route.forAction(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster1, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
|
|
@ -394,7 +394,7 @@ public class XdsNameResolverTest {
|
|||
public void resolved_noTimeout() {
|
||||
resolver.start(mockListener);
|
||||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
Route route = Route.create(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
Route route = Route.forAction(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster1, Collections.<HashPolicy>emptyList(), null), // per-route timeout unset
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
|
|
@ -412,7 +412,7 @@ public class XdsNameResolverTest {
|
|||
public void resolved_fallbackToHttpMaxStreamDurationAsTimeout() {
|
||||
resolver.start(mockListener);
|
||||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
Route route = Route.create(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
Route route = Route.forAction(RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster1, Collections.<HashPolicy>emptyList(), null), // per-route timeout unset
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
|
|
@ -436,7 +436,7 @@ public class XdsNameResolverTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void resolved_simpleCallFailedToRoute() {
|
||||
public void resolved_simpleCallFailedToRoute_noMatchingRoute() {
|
||||
InternalConfigSelector configSelector = resolveToClusters();
|
||||
CallInfo call = new CallInfo("FooService", "barMethod");
|
||||
Result selectResult = configSelector.selectConfig(
|
||||
|
|
@ -448,13 +448,48 @@ public class XdsNameResolverTest {
|
|||
verifyNoMoreInteractions(mockListener);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void resolved_simpleCallFailedToRoute_routeWithNonForwardingAction() {
|
||||
resolver.start(mockListener);
|
||||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.forNonForwardingAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of())));
|
||||
verify(mockListener).onResult(resolutionResultCaptor.capture());
|
||||
ResolutionResult result = resolutionResultCaptor.getValue();
|
||||
assertThat(result.getAddresses()).isEmpty();
|
||||
assertServiceConfigForLoadBalancingConfig(
|
||||
Collections.singletonList(cluster2),
|
||||
(Map<String, ?>) result.getServiceConfig().getConfig());
|
||||
assertThat(result.getAttributes().get(InternalXdsAttributes.XDS_CLIENT_POOL)).isNotNull();
|
||||
assertThat(result.getAttributes().get(InternalXdsAttributes.CALL_COUNTER_PROVIDER)).isNotNull();
|
||||
InternalConfigSelector configSelector = result.getAttributes().get(InternalConfigSelector.KEY);
|
||||
// Simulates making a call1 RPC.
|
||||
Result selectResult = configSelector.selectConfig(
|
||||
new PickSubchannelArgsImpl(call1.methodDescriptor, new Metadata(), CallOptions.DEFAULT));
|
||||
Status status = selectResult.getStatus();
|
||||
assertThat(status.isOk()).isFalse();
|
||||
assertThat(status.getCode()).isEqualTo(Code.UNAVAILABLE);
|
||||
assertThat(status.getDescription())
|
||||
.isEqualTo("Could not route RPC to Route with non-forwarding action");
|
||||
verifyNoMoreInteractions(mockListener);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolved_rpcHashingByHeader_withoutSubstitution() {
|
||||
resolver.start(mockListener);
|
||||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Collections.singletonList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(
|
||||
"/" + TestMethodDescriptors.voidMethod().getFullMethodName()),
|
||||
RouteAction.forCluster(cluster1, Collections.singletonList(HashPolicy.forHeader(
|
||||
|
|
@ -485,7 +520,7 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Collections.singletonList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(
|
||||
"/" + TestMethodDescriptors.voidMethod().getFullMethodName()),
|
||||
RouteAction.forCluster(cluster1, Collections.singletonList(HashPolicy.forHeader(
|
||||
|
|
@ -522,7 +557,7 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Collections.singletonList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(
|
||||
"/" + TestMethodDescriptors.voidMethod().getFullMethodName()),
|
||||
RouteAction.forCluster(cluster1, Collections.singletonList(
|
||||
|
|
@ -553,7 +588,7 @@ public class XdsNameResolverTest {
|
|||
xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Collections.singletonList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(
|
||||
"/" + TestMethodDescriptors.voidMethod().getFullMethodName()),
|
||||
RouteAction.forCluster(cluster1, Collections.singletonList(
|
||||
|
|
@ -584,13 +619,13 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
"another-cluster", Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(20L)),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
cluster2, Collections.<HashPolicy>emptyList(), TimeUnit.SECONDS.toNanos(15L)),
|
||||
|
|
@ -623,13 +658,13 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(
|
||||
"another-cluster", Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(20L)),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
|
|
@ -658,12 +693,12 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster("another-cluster", Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(20L)),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
|
|
@ -677,12 +712,12 @@ public class XdsNameResolverTest {
|
|||
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster("another-cluster", Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
|
|
@ -698,19 +733,19 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Collections.singletonList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of())));
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster1, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
|
|
@ -727,7 +762,7 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Collections.singletonList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forWeightedClusters(
|
||||
Arrays.asList(
|
||||
|
|
@ -790,12 +825,12 @@ public class XdsNameResolverTest {
|
|||
FakeXdsClient xdsClient = (FakeXdsClient) resolver.getXdsClient();
|
||||
xdsClient.deliverLdsUpdate(
|
||||
Arrays.asList(
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call1.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster1, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
ImmutableMap.<String, FilterConfig>of()),
|
||||
Route.create(
|
||||
Route.forAction(
|
||||
RouteMatch.withPathExactOnly(call2.getFullMethodNameForPath()),
|
||||
RouteAction.forCluster(cluster2, Collections.<HashPolicy>emptyList(),
|
||||
TimeUnit.SECONDS.toNanos(15L)),
|
||||
|
|
@ -1591,7 +1626,8 @@ public class XdsNameResolverTest {
|
|||
}
|
||||
|
||||
void deliverLdsUpdate(long httpMaxStreamDurationNano, List<VirtualHost> virtualHosts) {
|
||||
ldsWatcher.onChanged(new LdsUpdate(httpMaxStreamDurationNano, virtualHosts, null));
|
||||
ldsWatcher.onChanged(LdsUpdate.forApiListener(HttpConnectionManager.forVirtualHosts(
|
||||
httpMaxStreamDurationNano, virtualHosts, null)));
|
||||
}
|
||||
|
||||
void deliverLdsUpdate(final List<Route> routes) {
|
||||
|
|
@ -1599,7 +1635,8 @@ public class XdsNameResolverTest {
|
|||
VirtualHost.create(
|
||||
"virtual-host", Collections.singletonList(AUTHORITY), routes,
|
||||
ImmutableMap.<String, FilterConfig>of());
|
||||
ldsWatcher.onChanged(new LdsUpdate(0L, Collections.singletonList(virtualHost), null));
|
||||
ldsWatcher.onChanged(LdsUpdate.forApiListener(HttpConnectionManager.forVirtualHosts(
|
||||
0L, Collections.singletonList(virtualHost), null)));
|
||||
}
|
||||
|
||||
void deliverLdsUpdateWithFaultInjection(
|
||||
|
|
@ -1625,7 +1662,7 @@ public class XdsNameResolverTest {
|
|||
overrideConfig = routeFaultConfig == null
|
||||
? ImmutableMap.<String, FilterConfig>of()
|
||||
: ImmutableMap.<String, FilterConfig>of(FAULT_FILTER_INSTANCE_NAME, routeFaultConfig);
|
||||
Route route = Route.create(
|
||||
Route route = Route.forAction(
|
||||
RouteMatch.create(
|
||||
PathMatcher.fromPrefix("/", false), Collections.<HeaderMatcher>emptyList(), null),
|
||||
RouteAction.forWeightedClusters(
|
||||
|
|
@ -1642,7 +1679,8 @@ public class XdsNameResolverTest {
|
|||
Collections.singletonList(AUTHORITY),
|
||||
Collections.singletonList(route),
|
||||
overrideConfig);
|
||||
ldsWatcher.onChanged(new LdsUpdate(0L, Collections.singletonList(virtualHost), filterChain));
|
||||
ldsWatcher.onChanged(LdsUpdate.forApiListener(HttpConnectionManager.forVirtualHosts(
|
||||
0L, Collections.singletonList(virtualHost), filterChain)));
|
||||
}
|
||||
|
||||
void deliverLdsUpdateWithNoRouterFilter() {
|
||||
|
|
@ -1651,8 +1689,8 @@ public class XdsNameResolverTest {
|
|||
Collections.singletonList(AUTHORITY),
|
||||
Collections.<Route>emptyList(),
|
||||
Collections.<String, FilterConfig>emptyMap());
|
||||
ldsWatcher.onChanged(new LdsUpdate(
|
||||
0L, Collections.singletonList(virtualHost), ImmutableList.<NamedFilterConfig>of()));
|
||||
ldsWatcher.onChanged(LdsUpdate.forApiListener(HttpConnectionManager.forVirtualHosts(
|
||||
0L, Collections.singletonList(virtualHost), ImmutableList.<NamedFilterConfig>of())));
|
||||
}
|
||||
|
||||
void deliverLdsUpdateForRdsNameWithFaultInjection(
|
||||
|
|
@ -1664,11 +1702,13 @@ public class XdsNameResolverTest {
|
|||
ImmutableList<NamedFilterConfig> filterChain = ImmutableList.of(
|
||||
new NamedFilterConfig(FAULT_FILTER_INSTANCE_NAME, httpFilterFaultConfig),
|
||||
new NamedFilterConfig(ROUTER_FILTER_INSTANCE_NAME, RouterFilter.ROUTER_CONFIG));
|
||||
ldsWatcher.onChanged(new LdsUpdate(0L, rdsName, filterChain));
|
||||
ldsWatcher.onChanged(LdsUpdate.forApiListener(HttpConnectionManager.forRdsName(
|
||||
0L, rdsName, filterChain)));
|
||||
}
|
||||
|
||||
void deliverLdsUpdateForRdsName(String rdsName) {
|
||||
ldsWatcher.onChanged(new LdsUpdate(0, rdsName, null));
|
||||
ldsWatcher.onChanged(LdsUpdate.forApiListener(HttpConnectionManager.forRdsName(
|
||||
0, rdsName, null)));
|
||||
}
|
||||
|
||||
void deliverLdsResourceNotFound() {
|
||||
|
|
@ -1690,7 +1730,7 @@ public class XdsNameResolverTest {
|
|||
overrideConfig = routFaultConfig == null
|
||||
? ImmutableMap.<String, FilterConfig>of()
|
||||
: ImmutableMap.<String, FilterConfig>of(FAULT_FILTER_INSTANCE_NAME, routFaultConfig);
|
||||
Route route = Route.create(
|
||||
Route route = Route.forAction(
|
||||
RouteMatch.create(
|
||||
PathMatcher.fromPrefix("/", false), Collections.<HeaderMatcher>emptyList(), null),
|
||||
RouteAction.forWeightedClusters(
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ import io.grpc.testing.protobuf.SimpleResponse;
|
|||
import io.grpc.testing.protobuf.SimpleServiceGrpc;
|
||||
import io.grpc.xds.EnvoyServerProtoData.DownstreamTlsContext;
|
||||
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
|
||||
import io.grpc.xds.Filter.NamedFilterConfig;
|
||||
import io.grpc.xds.XdsClient.LdsUpdate;
|
||||
import io.grpc.xds.internal.sds.CommonTlsContextTestsUtil;
|
||||
import io.grpc.xds.internal.sds.SslContextProviderSupplier;
|
||||
import io.grpc.xds.internal.sds.TlsContextManagerImpl;
|
||||
|
|
@ -59,6 +61,7 @@ import java.net.URI;
|
|||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLHandshakeException;
|
||||
|
|
@ -336,7 +339,7 @@ public class XdsSdsClientServerTest {
|
|||
TlsContextManager tlsContextManager) {
|
||||
EnvoyServerProtoData.Listener listener = buildListener("listener1", "0.0.0.0", tlsContext,
|
||||
tlsContextManager);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
}
|
||||
|
||||
|
|
@ -366,8 +369,12 @@ public class XdsSdsClientServerTest {
|
|||
Arrays.<Integer>asList(),
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch, tlsContext, tlsContextManager);
|
||||
// HttpConnectionManager currently not used for server side.
|
||||
HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName(
|
||||
0L, "does not matter", Collections.<NamedFilterConfig>emptyList());
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch, httpConnectionManager, tlsContext,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(name, address, Arrays.asList(defaultFilterChain), null);
|
||||
return listener;
|
||||
|
|
|
|||
|
|
@ -23,9 +23,12 @@ import static org.mockito.Mockito.when;
|
|||
|
||||
import io.grpc.InsecureChannelCredentials;
|
||||
import io.grpc.internal.ObjectPool;
|
||||
import io.grpc.xds.Filter.NamedFilterConfig;
|
||||
import io.grpc.xds.XdsClient.LdsUpdate;
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.annotation.Nullable;
|
||||
|
|
@ -121,7 +124,7 @@ class XdsServerTestHelper {
|
|||
EnvoyServerProtoData.DownstreamTlsContext tlsContext, TlsContextManager tlsContextManager) {
|
||||
EnvoyServerProtoData.Listener listener = buildTestListener("listener1", "10.1.2.3",
|
||||
Arrays.<Integer>asList(), tlsContext, null, tlsContextManager);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +135,7 @@ class XdsServerTestHelper {
|
|||
TlsContextManager tlsContextManager) {
|
||||
EnvoyServerProtoData.Listener listener = buildTestListener("listener1", "10.1.2.3", sourcePorts,
|
||||
tlsContext, tlsContextForDefaultFilterChain, tlsContextManager);
|
||||
XdsClient.LdsUpdate listenerUpdate = new XdsClient.LdsUpdate(listener);
|
||||
LdsUpdate listenerUpdate = LdsUpdate.forTcpListener(listener);
|
||||
registeredWatcher.onChanged(listenerUpdate);
|
||||
}
|
||||
|
||||
|
|
@ -158,11 +161,15 @@ class XdsServerTestHelper {
|
|||
sourcePorts,
|
||||
Arrays.<String>asList(),
|
||||
null);
|
||||
EnvoyServerProtoData.FilterChain filterChain1 =
|
||||
new EnvoyServerProtoData.FilterChain(filterChainMatch1, tlsContext, tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain =
|
||||
new EnvoyServerProtoData.FilterChain(null, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
// HttpConnectionManager currently not used for server side.
|
||||
HttpConnectionManager httpConnectionManager = HttpConnectionManager.forRdsName(
|
||||
0L, "does not matter", Collections.<NamedFilterConfig>emptyList());
|
||||
EnvoyServerProtoData.FilterChain filterChain1 = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-foo", filterChainMatch1, httpConnectionManager, tlsContext,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.FilterChain defaultFilterChain = new EnvoyServerProtoData.FilterChain(
|
||||
"filter-chain-bar", null, httpConnectionManager, tlsContextForDefaultFilterChain,
|
||||
tlsContextManager);
|
||||
EnvoyServerProtoData.Listener listener =
|
||||
new EnvoyServerProtoData.Listener(
|
||||
name, address, Arrays.asList(filterChain1), defaultFilterChain);
|
||||
|
|
|
|||
Loading…
Reference in New Issue