Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions xds/src/main/java/io/grpc/xds/FaultFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ public FaultFilter newInstance(String name) {
}

@Override
public ConfigOrError<FaultConfig> parseFilterConfig(Message rawProtoMessage) {
public ConfigOrError<FaultConfig> parseFilterConfig(
Message rawProtoMessage, FilterContext context) {
HTTPFault httpFaultProto;
if (!(rawProtoMessage instanceof Any)) {
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
Expand All @@ -119,8 +120,9 @@ public ConfigOrError<FaultConfig> parseFilterConfig(Message rawProtoMessage) {
}

@Override
public ConfigOrError<FaultConfig> parseFilterConfigOverride(Message rawProtoMessage) {
return parseFilterConfig(rawProtoMessage);
public ConfigOrError<FaultConfig> parseFilterConfigOverride(
Message rawProtoMessage, FilterContext context) {
return parseFilterConfig(rawProtoMessage, context);
}

private static ConfigOrError<FaultConfig> parseHttpFault(HTTPFault httpFault) {
Expand Down
31 changes: 29 additions & 2 deletions xds/src/main/java/io/grpc/xds/Filter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@

package io.grpc.xds;


import com.google.auto.value.AutoValue;
import com.google.common.base.MoreObjects;
import com.google.protobuf.Message;
import io.grpc.ClientInterceptor;
import io.grpc.ServerInterceptor;
import io.grpc.xds.client.Bootstrapper.BootstrapInfo;
import io.grpc.xds.client.Bootstrapper.ServerInfo;
import java.io.Closeable;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
Expand Down Expand Up @@ -93,13 +97,15 @@ default boolean isServerFilter() {
* Parses the top-level filter config from raw proto message. The message may be either a {@link
* com.google.protobuf.Any} or a {@link com.google.protobuf.Struct}.
*/
ConfigOrError<? extends FilterConfig> parseFilterConfig(Message rawProtoMessage);
ConfigOrError<? extends FilterConfig> parseFilterConfig(
Message rawProtoMessage, FilterContext context);

/**
* Parses the per-filter override filter config from raw proto message. The message may be
* either a {@link com.google.protobuf.Any} or a {@link com.google.protobuf.Struct}.
*/
ConfigOrError<? extends FilterConfig> parseFilterConfigOverride(Message rawProtoMessage);
ConfigOrError<? extends FilterConfig> parseFilterConfigOverride(
Message rawProtoMessage, FilterContext context);
}

/** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for clients. */
Expand All @@ -125,6 +131,27 @@ default ServerInterceptor buildServerInterceptor(
@Override
default void close() {}

/** Context carrying dynamic metadata for a filter. */
@AutoValue
abstract static class FilterContext {
abstract BootstrapInfo bootstrapInfo();

abstract ServerInfo serverInfo();

static Builder builder() {
return new AutoValue_Filter_FilterContext.Builder();
}

@AutoValue.Builder
abstract static class Builder {
abstract Builder bootstrapInfo(BootstrapInfo info);

abstract Builder serverInfo(ServerInfo info);

abstract FilterContext build();
}
}

/** Filter config with instance name. */
final class NamedFilterConfig {
// filter instance name
Expand Down
7 changes: 4 additions & 3 deletions xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ public GcpAuthenticationFilter newInstance(String name) {
}

@Override
public ConfigOrError<GcpAuthenticationConfig> parseFilterConfig(Message rawProtoMessage) {
public ConfigOrError<GcpAuthenticationConfig> parseFilterConfig(
Message rawProtoMessage, FilterContext context) {
GcpAuthnFilterConfig gcpAuthnProto;
if (!(rawProtoMessage instanceof Any)) {
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
Expand Down Expand Up @@ -121,8 +122,8 @@ public ConfigOrError<GcpAuthenticationConfig> parseFilterConfig(Message rawProto

@Override
public ConfigOrError<GcpAuthenticationConfig> parseFilterConfigOverride(
Message rawProtoMessage) {
return parseFilterConfig(rawProtoMessage);
Message rawProtoMessage, FilterContext context) {
return parseFilterConfig(rawProtoMessage, context);
}
}

Expand Down
109 changes: 100 additions & 9 deletions xds/src/main/java/io/grpc/xds/GrpcBootstrapperImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,20 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.errorprone.annotations.concurrent.GuardedBy;
import io.grpc.CallCredentials;
import io.grpc.ChannelCredentials;
import io.grpc.internal.JsonUtil;
import io.grpc.xds.client.BootstrapperImpl;
import io.grpc.xds.client.XdsInitializationException;
import io.grpc.xds.client.XdsLogger;
import io.grpc.xds.internal.grpcservice.AllowedGrpcService;
import io.grpc.xds.internal.grpcservice.AllowedGrpcServices;
import io.grpc.xds.internal.grpcservice.ChannelCredsConfig;
import io.grpc.xds.internal.grpcservice.ConfiguredChannelCredentials;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;

class GrpcBootstrapperImpl extends BootstrapperImpl {
Expand Down Expand Up @@ -97,7 +103,8 @@ protected String getJsonContent() throws XdsInitializationException, IOException
@Override
protected Object getImplSpecificConfig(Map<String, ?> serverConfig, String serverUri)
throws XdsInitializationException {
return getChannelCredentials(serverConfig, serverUri);
ConfiguredChannelCredentials configuredChannel = getChannelCredentials(serverConfig, serverUri);
return configuredChannel != null ? configuredChannel.channelCredentials() : null;
}

@GuardedBy("GrpcBootstrapperImpl.class")
Expand All @@ -120,26 +127,26 @@ static synchronized BootstrapInfo defaultBootstrap() throws XdsInitializationExc
return defaultBootstrap;
}

private static ChannelCredentials getChannelCredentials(Map<String, ?> serverConfig,
String serverUri)
private static ConfiguredChannelCredentials getChannelCredentials(Map<String, ?> serverConfig,
String serverUri)
throws XdsInitializationException {
List<?> rawChannelCredsList = JsonUtil.getList(serverConfig, "channel_creds");
if (rawChannelCredsList == null || rawChannelCredsList.isEmpty()) {
throw new XdsInitializationException(
"Invalid bootstrap: server " + serverUri + " 'channel_creds' required");
}
ChannelCredentials channelCredentials =
ConfiguredChannelCredentials credentials =
parseChannelCredentials(JsonUtil.checkObjectList(rawChannelCredsList), serverUri);
if (channelCredentials == null) {
if (credentials == null) {
throw new XdsInitializationException(
"Server " + serverUri + ": no supported channel credentials found");
}
return channelCredentials;
return credentials;
}

@Nullable
private static ChannelCredentials parseChannelCredentials(List<Map<String, ?>> jsonList,
String serverUri)
private static ConfiguredChannelCredentials parseChannelCredentials(List<Map<String, ?>> jsonList,
String serverUri)
throws XdsInitializationException {
for (Map<String, ?> channelCreds : jsonList) {
String type = JsonUtil.getString(channelCreds, "type");
Expand All @@ -155,9 +162,93 @@ private static ChannelCredentials parseChannelCredentials(List<Map<String, ?>> j
config = ImmutableMap.of();
}

return provider.newChannelCredentials(config);
ChannelCredentials creds = provider.newChannelCredentials(config);
if (creds == null) {
return null;
}
return ConfiguredChannelCredentials.create(creds, new JsonChannelCredsConfig(type, config));
}
}
return null;
}

@Override
protected Optional<Object> parseAllowedGrpcServices(
@Nullable Map<String, ?> rawAllowedGrpcServices)
throws XdsInitializationException {
if (rawAllowedGrpcServices == null || rawAllowedGrpcServices.isEmpty()) {
return Optional.of(AllowedGrpcServices.empty());
}

ImmutableMap.Builder<String, AllowedGrpcService> builder =
ImmutableMap.builder();
for (String targetUri : rawAllowedGrpcServices.keySet()) {
Map<String, ?> serviceConfig = JsonUtil.getObject(rawAllowedGrpcServices, targetUri);
if (serviceConfig == null) {
throw new XdsInitializationException(
"Invalid allowed_grpc_services config for " + targetUri);
}
ConfiguredChannelCredentials configuredChannel =
getChannelCredentials(serviceConfig, targetUri);

Optional<CallCredentials> callCredentials = Optional.empty();
List<?> rawCallCredsList = JsonUtil.getList(serviceConfig, "call_creds");
if (rawCallCredsList != null && !rawCallCredsList.isEmpty()) {
callCredentials =
parseCallCredentials(JsonUtil.checkObjectList(rawCallCredsList), targetUri);
}

AllowedGrpcService.Builder b = AllowedGrpcService.builder()
.configuredChannelCredentials(configuredChannel);
callCredentials.ifPresent(b::callCredentials);
builder.put(targetUri, b.build());
}
return Optional.of(AllowedGrpcServices.create(builder.build()));
}

@SuppressWarnings("unused")
private static Optional<CallCredentials> parseCallCredentials(List<Map<String, ?>> jsonList,
String targetUri)
throws XdsInitializationException {
// TODO(sauravzg): Currently no xDS call credentials providers are implemented (no
// XdsCallCredentialsRegistry).
// As per A102/A97, we should just ignore unsupported call credentials types
// without throwing an exception.
return Optional.empty();
}

private static final class JsonChannelCredsConfig implements ChannelCredsConfig {
private final String type;
private final Map<String, ?> config;

JsonChannelCredsConfig(String type, Map<String, ?> config) {
this.type = type;
this.config = config;
}

@Override
public String type() {
return type;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
JsonChannelCredsConfig that = (JsonChannelCredsConfig) o;
return java.util.Objects.equals(type, that.type)
&& java.util.Objects.equals(config, that.config);
}

@Override
public int hashCode() {
return java.util.Objects.hash(type, config);
}
}

}

6 changes: 4 additions & 2 deletions xds/src/main/java/io/grpc/xds/RbacFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ public RbacFilter newInstance(String name) {
}

@Override
public ConfigOrError<RbacConfig> parseFilterConfig(Message rawProtoMessage) {
public ConfigOrError<RbacConfig> parseFilterConfig(
Message rawProtoMessage, FilterContext context) {
RBAC rbacProto;
if (!(rawProtoMessage instanceof Any)) {
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
Expand All @@ -109,7 +110,8 @@ public ConfigOrError<RbacConfig> parseFilterConfig(Message rawProtoMessage) {
}

@Override
public ConfigOrError<RbacConfig> parseFilterConfigOverride(Message rawProtoMessage) {
public ConfigOrError<RbacConfig> parseFilterConfigOverride(
Message rawProtoMessage, FilterContext context) {
RBACPerRoute rbacPerRoute;
if (!(rawProtoMessage instanceof Any)) {
return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass());
Expand Down
5 changes: 3 additions & 2 deletions xds/src/main/java/io/grpc/xds/RouterFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ public RouterFilter newInstance(String name) {
}

@Override
public ConfigOrError<? extends FilterConfig> parseFilterConfig(Message rawProtoMessage) {
public ConfigOrError<? extends FilterConfig> parseFilterConfig(
Message rawProtoMessage, FilterContext context) {
return ConfigOrError.fromConfig(ROUTER_CONFIG);
}

@Override
public ConfigOrError<? extends FilterConfig> parseFilterConfigOverride(
Message rawProtoMessage) {
Message rawProtoMessage, FilterContext context) {
return ConfigOrError.fromError("Router Filter should not have override config");
}
}
Expand Down
13 changes: 10 additions & 3 deletions xds/src/main/java/io/grpc/xds/XdsListenerResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager(
"HttpConnectionManager contains duplicate HttpFilter: " + filterName);
}
StructOrError<Filter.FilterConfig> filterConfig =
parseHttpFilter(httpFilter, filterRegistry, isForClient);
parseHttpFilter(httpFilter, filterRegistry, isForClient, args);
if ((i == proto.getHttpFiltersCount() - 1)
&& (filterConfig == null || !isTerminalFilter(filterConfig.getStruct()))) {
throw new ResourceInvalidException("The last HttpFilter must be a terminal filter: "
Expand Down Expand Up @@ -581,7 +581,8 @@ private static boolean isTerminalFilter(Filter.FilterConfig filterConfig) {
@Nullable // Returns null if the filter is optional but not supported.
static StructOrError<Filter.FilterConfig> parseHttpFilter(
io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
httpFilter, FilterRegistry filterRegistry, boolean isForClient) {
httpFilter, FilterRegistry filterRegistry, boolean isForClient,
XdsResourceType.Args args) {
String filterName = httpFilter.getName();
boolean isOptional = httpFilter.getIsOptional();
if (!httpFilter.hasTypedConfig()) {
Expand Down Expand Up @@ -616,7 +617,13 @@ static StructOrError<Filter.FilterConfig> parseHttpFilter(
"HttpFilter [" + filterName + "](" + typeUrl + ") is required but unsupported for " + (
isForClient ? "client" : "server"));
}
ConfigOrError<? extends FilterConfig> filterConfig = provider.parseFilterConfig(rawConfig);

Filter.FilterContext filterContext = Filter.FilterContext.builder()
.bootstrapInfo(args.getBootstrapInfo())
.serverInfo(args.getServerInfo())
.build();
ConfigOrError<? extends FilterConfig> filterConfig =
provider.parseFilterConfig(rawConfig, filterContext);
if (filterConfig.errorDetail != null) {
return StructOrError.fromError(
"Invalid filter config for HttpFilter [" + filterName + "]: " + filterConfig.errorDetail);
Expand Down
19 changes: 12 additions & 7 deletions xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ private static StructOrError<VirtualHost> parseVirtualHost(
routes.add(route.getStruct());
}
StructOrError<Map<String, Filter.FilterConfig>> overrideConfigs =
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry);
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry, args);
if (overrideConfigs.getErrorDetail() != null) {
return StructOrError.fromError(
"VirtualHost [" + proto.getName() + "] contains invalid HttpFilter config: "
Expand All @@ -210,7 +210,12 @@ private static StructOrError<VirtualHost> parseVirtualHost(

@VisibleForTesting
static StructOrError<Map<String, FilterConfig>> parseOverrideFilterConfigs(
Map<String, Any> rawFilterConfigMap, FilterRegistry filterRegistry) {
Map<String, Any> rawFilterConfigMap, FilterRegistry filterRegistry,
XdsResourceType.Args args) {
Filter.FilterContext context = Filter.FilterContext.builder()
.bootstrapInfo(args.getBootstrapInfo())
.serverInfo(args.getServerInfo())
.build();
Map<String, FilterConfig> overrideConfigs = new HashMap<>();
for (String name : rawFilterConfigMap.keySet()) {
Any anyConfig = rawFilterConfigMap.get(name);
Expand Down Expand Up @@ -254,7 +259,7 @@ static StructOrError<Map<String, FilterConfig>> parseOverrideFilterConfigs(
"HttpFilter [" + name + "](" + typeUrl + ") is required but unsupported");
}
ConfigOrError<? extends Filter.FilterConfig> filterConfig =
provider.parseFilterConfigOverride(rawConfig);
provider.parseFilterConfigOverride(rawConfig, context);
if (filterConfig.errorDetail != null) {
return StructOrError.fromError(
"Invalid filter config for HttpFilter [" + name + "]: " + filterConfig.errorDetail);
Expand All @@ -281,7 +286,7 @@ static StructOrError<Route> parseRoute(
}

StructOrError<Map<String, FilterConfig>> overrideConfigsOrError =
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry);
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry, args);
if (overrideConfigsOrError.getErrorDetail() != null) {
return StructOrError.fromError(
"Route [" + proto.getName() + "] contains invalid HttpFilter config: "
Expand Down Expand Up @@ -490,7 +495,7 @@ static StructOrError<RouteAction> parseRouteAction(
for (io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight clusterWeight
: clusterWeights) {
StructOrError<ClusterWeight> clusterWeightOrError =
parseClusterWeight(clusterWeight, filterRegistry);
parseClusterWeight(clusterWeight, filterRegistry, args);
if (clusterWeightOrError.getErrorDetail() != null) {
return StructOrError.fromError("RouteAction contains invalid ClusterWeight: "
+ clusterWeightOrError.getErrorDetail());
Expand Down Expand Up @@ -599,9 +604,9 @@ private static StructOrError<VirtualHost.Route.RouteAction.RetryPolicy> parseRet
@VisibleForTesting
static StructOrError<VirtualHost.Route.RouteAction.ClusterWeight> parseClusterWeight(
io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight proto,
FilterRegistry filterRegistry) {
FilterRegistry filterRegistry, XdsResourceType.Args args) {
StructOrError<Map<String, Filter.FilterConfig>> overrideConfigs =
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry);
parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry, args);
if (overrideConfigs.getErrorDetail() != null) {
return StructOrError.fromError(
"ClusterWeight [" + proto.getName() + "] contains invalid HttpFilter config: "
Expand Down
Loading
Loading