diff --git a/xds/src/main/java/io/grpc/xds/FaultFilter.java b/xds/src/main/java/io/grpc/xds/FaultFilter.java index 0f3bb5b0557..e0533889d74 100644 --- a/xds/src/main/java/io/grpc/xds/FaultFilter.java +++ b/xds/src/main/java/io/grpc/xds/FaultFilter.java @@ -104,7 +104,8 @@ public FaultFilter newInstance(String name) { } @Override - public ConfigOrError parseFilterConfig(Message rawProtoMessage) { + public ConfigOrError parseFilterConfig( + Message rawProtoMessage, FilterContext context) { HTTPFault httpFaultProto; if (!(rawProtoMessage instanceof Any)) { return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass()); @@ -119,8 +120,9 @@ public ConfigOrError parseFilterConfig(Message rawProtoMessage) { } @Override - public ConfigOrError parseFilterConfigOverride(Message rawProtoMessage) { - return parseFilterConfig(rawProtoMessage); + public ConfigOrError parseFilterConfigOverride( + Message rawProtoMessage, FilterContext context) { + return parseFilterConfig(rawProtoMessage, context); } private static ConfigOrError parseHttpFault(HTTPFault httpFault) { diff --git a/xds/src/main/java/io/grpc/xds/Filter.java b/xds/src/main/java/io/grpc/xds/Filter.java index 416d929becf..d70b3063a50 100644 --- a/xds/src/main/java/io/grpc/xds/Filter.java +++ b/xds/src/main/java/io/grpc/xds/Filter.java @@ -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; @@ -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 parseFilterConfig(Message rawProtoMessage); + ConfigOrError 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 parseFilterConfigOverride(Message rawProtoMessage); + ConfigOrError parseFilterConfigOverride( + Message rawProtoMessage, FilterContext context); } /** Uses the FilterConfigs produced above to produce an HTTP filter interceptor for clients. */ @@ -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 diff --git a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java index 8ec02f4f809..78d20edec46 100644 --- a/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java +++ b/xds/src/main/java/io/grpc/xds/GcpAuthenticationFilter.java @@ -86,7 +86,8 @@ public GcpAuthenticationFilter newInstance(String name) { } @Override - public ConfigOrError parseFilterConfig(Message rawProtoMessage) { + public ConfigOrError parseFilterConfig( + Message rawProtoMessage, FilterContext context) { GcpAuthnFilterConfig gcpAuthnProto; if (!(rawProtoMessage instanceof Any)) { return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass()); @@ -121,8 +122,8 @@ public ConfigOrError parseFilterConfig(Message rawProto @Override public ConfigOrError parseFilterConfigOverride( - Message rawProtoMessage) { - return parseFilterConfig(rawProtoMessage); + Message rawProtoMessage, FilterContext context) { + return parseFilterConfig(rawProtoMessage, context); } } diff --git a/xds/src/main/java/io/grpc/xds/RbacFilter.java b/xds/src/main/java/io/grpc/xds/RbacFilter.java index 91df1e68802..035bfd06607 100644 --- a/xds/src/main/java/io/grpc/xds/RbacFilter.java +++ b/xds/src/main/java/io/grpc/xds/RbacFilter.java @@ -94,7 +94,8 @@ public RbacFilter newInstance(String name) { } @Override - public ConfigOrError parseFilterConfig(Message rawProtoMessage) { + public ConfigOrError parseFilterConfig( + Message rawProtoMessage, FilterContext context) { RBAC rbacProto; if (!(rawProtoMessage instanceof Any)) { return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass()); @@ -109,7 +110,8 @@ public ConfigOrError parseFilterConfig(Message rawProtoMessage) { } @Override - public ConfigOrError parseFilterConfigOverride(Message rawProtoMessage) { + public ConfigOrError parseFilterConfigOverride( + Message rawProtoMessage, FilterContext context) { RBACPerRoute rbacPerRoute; if (!(rawProtoMessage instanceof Any)) { return ConfigOrError.fromError("Invalid config type: " + rawProtoMessage.getClass()); diff --git a/xds/src/main/java/io/grpc/xds/RouterFilter.java b/xds/src/main/java/io/grpc/xds/RouterFilter.java index 504c4213149..c80e57c9010 100644 --- a/xds/src/main/java/io/grpc/xds/RouterFilter.java +++ b/xds/src/main/java/io/grpc/xds/RouterFilter.java @@ -61,13 +61,14 @@ public RouterFilter newInstance(String name) { } @Override - public ConfigOrError parseFilterConfig(Message rawProtoMessage) { + public ConfigOrError parseFilterConfig( + Message rawProtoMessage, FilterContext context) { return ConfigOrError.fromConfig(ROUTER_CONFIG); } @Override public ConfigOrError parseFilterConfigOverride( - Message rawProtoMessage) { + Message rawProtoMessage, FilterContext context) { return ConfigOrError.fromError("Router Filter should not have override config"); } } diff --git a/xds/src/main/java/io/grpc/xds/XdsListenerResource.java b/xds/src/main/java/io/grpc/xds/XdsListenerResource.java index 041b659b4c3..4bf1b0066c2 100644 --- a/xds/src/main/java/io/grpc/xds/XdsListenerResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsListenerResource.java @@ -527,7 +527,7 @@ static io.grpc.xds.HttpConnectionManager parseHttpConnectionManager( "HttpConnectionManager contains duplicate HttpFilter: " + filterName); } StructOrError 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: " @@ -581,7 +581,8 @@ private static boolean isTerminalFilter(Filter.FilterConfig filterConfig) { @Nullable // Returns null if the filter is optional but not supported. static StructOrError 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()) { @@ -616,7 +617,13 @@ static StructOrError parseHttpFilter( "HttpFilter [" + filterName + "](" + typeUrl + ") is required but unsupported for " + ( isForClient ? "client" : "server")); } - ConfigOrError filterConfig = provider.parseFilterConfig(rawConfig); + + Filter.FilterContext filterContext = Filter.FilterContext.builder() + .bootstrapInfo(args.getBootstrapInfo()) + .serverInfo(args.getServerInfo()) + .build(); + ConfigOrError filterConfig = + provider.parseFilterConfig(rawConfig, filterContext); if (filterConfig.errorDetail != null) { return StructOrError.fromError( "Invalid filter config for HttpFilter [" + filterName + "]: " + filterConfig.errorDetail); diff --git a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java index 24ec0659b42..dc213a452d7 100644 --- a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java @@ -36,7 +36,6 @@ import io.envoyproxy.envoy.config.route.v3.ClusterSpecifierPlugin; import io.envoyproxy.envoy.config.route.v3.RetryPolicy.RetryBackOff; import io.envoyproxy.envoy.config.route.v3.RouteConfiguration; -import io.envoyproxy.envoy.type.v3.FractionalPercent; import io.grpc.Status; import io.grpc.internal.GrpcUtil; import io.grpc.xds.ClusterSpecifierPlugin.NamedPluginConfig; @@ -198,7 +197,7 @@ private static StructOrError parseVirtualHost( routes.add(route.getStruct()); } StructOrError> overrideConfigs = - parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry); + parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry, args); if (overrideConfigs.getErrorDetail() != null) { return StructOrError.fromError( "VirtualHost [" + proto.getName() + "] contains invalid HttpFilter config: " @@ -210,7 +209,12 @@ private static StructOrError parseVirtualHost( @VisibleForTesting static StructOrError> parseOverrideFilterConfigs( - Map rawFilterConfigMap, FilterRegistry filterRegistry) { + Map rawFilterConfigMap, FilterRegistry filterRegistry, + XdsResourceType.Args args) { + Filter.FilterContext context = Filter.FilterContext.builder() + .bootstrapInfo(args.getBootstrapInfo()) + .serverInfo(args.getServerInfo()) + .build(); Map overrideConfigs = new HashMap<>(); for (String name : rawFilterConfigMap.keySet()) { Any anyConfig = rawFilterConfigMap.get(name); @@ -254,7 +258,7 @@ static StructOrError> parseOverrideFilterConfigs( "HttpFilter [" + name + "](" + typeUrl + ") is required but unsupported"); } ConfigOrError filterConfig = - provider.parseFilterConfigOverride(rawConfig); + provider.parseFilterConfigOverride(rawConfig, context); if (filterConfig.errorDetail != null) { return StructOrError.fromError( "Invalid filter config for HttpFilter [" + name + "]: " + filterConfig.errorDetail); @@ -281,7 +285,7 @@ static StructOrError parseRoute( } StructOrError> overrideConfigsOrError = - parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry); + parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry, args); if (overrideConfigsOrError.getErrorDetail() != null) { return StructOrError.fromError( "Route [" + proto.getName() + "] contains invalid HttpFilter config: " @@ -331,12 +335,12 @@ static StructOrError parseRouteMatch( FractionMatcher fractionMatch = null; if (proto.hasRuntimeFraction()) { - StructOrError parsedFraction = - parseFractionMatcher(proto.getRuntimeFraction().getDefaultValue()); - if (parsedFraction.getErrorDetail() != null) { - return StructOrError.fromError(parsedFraction.getErrorDetail()); + try { + fractionMatch = + MatcherParser.parseFractionMatcher(proto.getRuntimeFraction().getDefaultValue()); + } catch (IllegalArgumentException e) { + return StructOrError.fromError(e.getMessage()); } - fractionMatch = parsedFraction.getStruct(); } List headerMatchers = new ArrayList<>(); @@ -377,26 +381,7 @@ static StructOrError parsePathMatcher( } } - private static StructOrError parseFractionMatcher(FractionalPercent proto) { - int numerator = proto.getNumerator(); - int denominator = 0; - switch (proto.getDenominator()) { - case HUNDRED: - denominator = 100; - break; - case TEN_THOUSAND: - denominator = 10_000; - break; - case MILLION: - denominator = 1_000_000; - break; - case UNRECOGNIZED: - default: - return StructOrError.fromError( - "Unrecognized fractional percent denominator: " + proto.getDenominator()); - } - return StructOrError.fromStruct(FractionMatcher.create(numerator, denominator)); - } + @VisibleForTesting static StructOrError parseHeaderMatcher( @@ -490,7 +475,7 @@ static StructOrError parseRouteAction( for (io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight clusterWeight : clusterWeights) { StructOrError clusterWeightOrError = - parseClusterWeight(clusterWeight, filterRegistry); + parseClusterWeight(clusterWeight, filterRegistry, args); if (clusterWeightOrError.getErrorDetail() != null) { return StructOrError.fromError("RouteAction contains invalid ClusterWeight: " + clusterWeightOrError.getErrorDetail()); @@ -599,9 +584,9 @@ private static StructOrError parseRet @VisibleForTesting static StructOrError parseClusterWeight( io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight proto, - FilterRegistry filterRegistry) { + FilterRegistry filterRegistry, XdsResourceType.Args args) { StructOrError> overrideConfigs = - parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry); + parseOverrideFilterConfigs(proto.getTypedPerFilterConfigMap(), filterRegistry, args); if (overrideConfigs.getErrorDetail() != null) { return StructOrError.fromError( "ClusterWeight [" + proto.getName() + "] contains invalid HttpFilter config: " diff --git a/xds/src/test/java/io/grpc/xds/FaultFilterTest.java b/xds/src/test/java/io/grpc/xds/FaultFilterTest.java index 8f0a33951b0..494df4bed92 100644 --- a/xds/src/test/java/io/grpc/xds/FaultFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/FaultFilterTest.java @@ -26,6 +26,10 @@ import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType; import io.grpc.Status.Code; import io.grpc.internal.GrpcUtil; +import io.grpc.xds.client.Bootstrapper.BootstrapInfo; +import io.grpc.xds.client.Bootstrapper.ServerInfo; +import io.grpc.xds.client.EnvoyProtoData.Node; +import java.util.Collections; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -45,11 +49,16 @@ public void filterType_clientOnly() { public void parseFaultAbort_convertHttpStatus() { Any rawConfig = Any.pack( HTTPFault.newBuilder().setAbort(FaultAbort.newBuilder().setHttpStatus(404)).build()); - FaultConfig faultConfig = FILTER_PROVIDER.parseFilterConfig(rawConfig).config; + FaultConfig faultConfig = FILTER_PROVIDER.parseFilterConfig( + rawConfig, getFilterContext()).config; + assertThat(faultConfig.faultAbort()).isNotNull(); assertThat(faultConfig.faultAbort().status().getCode()) .isEqualTo(GrpcUtil.httpStatusToGrpcStatus(404).getCode()); - FaultConfig faultConfigOverride = FILTER_PROVIDER.parseFilterConfigOverride(rawConfig).config; + FaultConfig faultConfigOverride = + FILTER_PROVIDER.parseFilterConfigOverride( + rawConfig, getFilterContext()).config; + assertThat(faultConfigOverride.faultAbort()).isNotNull(); assertThat(faultConfigOverride.faultAbort().status().getCode()) .isEqualTo(GrpcUtil.httpStatusToGrpcStatus(404).getCode()); } @@ -95,4 +104,17 @@ public void parseFaultAbort_withGrpcStatus() { .isEqualTo(FaultConfig.FractionalPercent.DenominatorType.MILLION); assertThat(faultAbort.status().getCode()).isEqualTo(Code.DEADLINE_EXCEEDED); } + + private static Filter.FilterContext getFilterContext() { + return Filter.FilterContext.builder() + .bootstrapInfo(BootstrapInfo.builder() + .servers(Collections.singletonList( + ServerInfo.create( + "test_target", Collections.emptyMap()))) + .node(Node.newBuilder().build()) + .build()) + .serverInfo(ServerInfo.create( + "test_target", Collections.emptyMap(), false, true, false, false)) + .build(); + } } diff --git a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java index f252c6f4ec1..579701580b2 100644 --- a/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/GcpAuthenticationFilterTest.java @@ -65,6 +65,9 @@ import io.grpc.xds.XdsEndpointResource.EdsUpdate; import io.grpc.xds.XdsListenerResource.LdsUpdate; import io.grpc.xds.XdsRouteConfigureResource.RdsUpdate; +import io.grpc.xds.client.Bootstrapper.BootstrapInfo; +import io.grpc.xds.client.Bootstrapper.ServerInfo; +import io.grpc.xds.client.EnvoyProtoData.Node; import io.grpc.xds.client.Locality; import io.grpc.xds.client.XdsResourceType; import io.grpc.xds.client.XdsResourceType.ResourceInvalidException; @@ -112,8 +115,8 @@ public void testParseFilterConfig_withValidConfig() { .build(); Any anyMessage = Any.pack(config); - ConfigOrError result = FILTER_PROVIDER.parseFilterConfig(anyMessage); - + ConfigOrError result = + FILTER_PROVIDER.parseFilterConfig(anyMessage, getFilterContext()); assertNotNull(result.config); assertNull(result.errorDetail); assertEquals(20L, result.config.getCacheSize()); @@ -126,8 +129,8 @@ public void testParseFilterConfig_withZeroCacheSize() { .build(); Any anyMessage = Any.pack(config); - ConfigOrError result = FILTER_PROVIDER.parseFilterConfig(anyMessage); - + ConfigOrError result = + FILTER_PROVIDER.parseFilterConfig(anyMessage, getFilterContext()); assertNull(result.config); assertNotNull(result.errorDetail); assertTrue(result.errorDetail.contains("cache_config.cache_size must be greater than zero")); @@ -137,7 +140,7 @@ public void testParseFilterConfig_withZeroCacheSize() { public void testParseFilterConfig_withInvalidMessageType() { Message invalidMessage = Empty.getDefaultInstance(); ConfigOrError result = - FILTER_PROVIDER.parseFilterConfig(invalidMessage); + FILTER_PROVIDER.parseFilterConfig(invalidMessage, getFilterContext()); assertNull(result.config); assertThat(result.errorDetail).contains("Invalid config type"); @@ -468,8 +471,9 @@ private static LdsUpdate getLdsUpdate() { private static RdsUpdate getRdsUpdate() { RouteConfiguration routeConfiguration = buildRouteConfiguration("my-server", RDS_NAME, CLUSTER_NAME); - XdsResourceType.Args args = new XdsResourceType.Args( - XdsTestUtils.EMPTY_BOOTSTRAPPER_SERVER_INFO, "0", "0", null, null, null); + XdsResourceType.Args args = + new XdsResourceType.Args(XdsTestUtils.EMPTY_BOOTSTRAPPER_SERVER_INFO, "0", "0", + XdsTestUtils.EMPTY_BOOTSTRAP, null, null); try { return XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration); } catch (ResourceInvalidException ex) { @@ -521,4 +525,17 @@ private static CdsUpdate getCdsUpdateWithIncorrectAudienceWrapper() throws IOExc .lbPolicyConfig(getWrrLbConfigAsMap()); return cdsUpdate.parsedMetadata(parsedMetadata.build()).build(); } + + private static Filter.FilterContext getFilterContext() { + return Filter.FilterContext.builder() + .bootstrapInfo(BootstrapInfo.builder() + .servers(Collections.singletonList( + ServerInfo.create( + "test_target", Collections.emptyMap()))) + .node(Node.newBuilder().build()) + .build()) + .serverInfo(ServerInfo.create( + "test_target", Collections.emptyMap(), false, true, false, false)) + .build(); + } } diff --git a/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java b/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java index be29e5e719f..7d88f9ebf94 100644 --- a/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java +++ b/xds/src/test/java/io/grpc/xds/GrpcXdsClientImplDataTest.java @@ -1049,7 +1049,9 @@ public void parseClusterWeight() { .setWeight(UInt32Value.newBuilder().setValue(30)) .build(); ClusterWeight clusterWeight = - XdsRouteConfigureResource.parseClusterWeight(proto, filterRegistry).getStruct(); + XdsRouteConfigureResource + .parseClusterWeight(proto, filterRegistry, getXdsResourceTypeArgs(true)) + .getStruct(); assertThat(clusterWeight.name()).isEqualTo("cluster-foo"); assertThat(clusterWeight.weight()).isEqualTo(30); } @@ -1255,7 +1257,8 @@ public void parseHttpFilter_unsupportedButOptional() { .setIsOptional(true) .setTypedConfig(Any.pack(StringValue.of("unsupported"))) .build(); - assertThat(XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, true)).isNull(); + assertThat(XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, true, + getXdsResourceTypeArgs(true))).isNull(); } private static class SimpleFilterConfig implements FilterConfig { @@ -1294,12 +1297,14 @@ public TestFilter newInstance(String name) { } @Override - public ConfigOrError parseFilterConfig(Message rawProtoMessage) { + public ConfigOrError parseFilterConfig(Message rawProtoMessage, + FilterContext context) { return ConfigOrError.fromConfig(new SimpleFilterConfig(rawProtoMessage)); } @Override - public ConfigOrError parseFilterConfigOverride(Message rawProtoMessage) { + public ConfigOrError parseFilterConfigOverride(Message rawProtoMessage, + FilterContext context) { return ConfigOrError.fromConfig(new SimpleFilterConfig(rawProtoMessage)); } } @@ -1319,7 +1324,7 @@ public void parseHttpFilter_typedStructMigration() { .setValue(rawStruct) .build())).build(); FilterConfig config = XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, - true).getStruct(); + true, getXdsResourceTypeArgs(true)).getStruct(); assertThat(((SimpleFilterConfig)config).getConfig()).isEqualTo(rawStruct); HttpFilter httpFilterNewTypeStruct = HttpFilter.newBuilder() @@ -1330,7 +1335,7 @@ public void parseHttpFilter_typedStructMigration() { .setValue(rawStruct) .build())).build(); config = XdsListenerResource.parseHttpFilter(httpFilterNewTypeStruct, filterRegistry, - true).getStruct(); + true, getXdsResourceTypeArgs(true)).getStruct(); assertThat(((SimpleFilterConfig)config).getConfig()).isEqualTo(rawStruct); } @@ -1356,7 +1361,7 @@ public void parseOverrideHttpFilter_typedStructMigration() { .build()) ); Map map = XdsRouteConfigureResource.parseOverrideFilterConfigs( - rawFilterMap, filterRegistry).getStruct(); + rawFilterMap, filterRegistry, getXdsResourceTypeArgs(true)).getStruct(); assertThat(((SimpleFilterConfig)map.get("struct-0")).getConfig()).isEqualTo(rawStruct0); assertThat(((SimpleFilterConfig)map.get("struct-1")).getConfig()).isEqualTo(rawStruct1); } @@ -1368,7 +1373,8 @@ public void parseHttpFilter_unsupportedAndRequired() { .setName("unsupported.filter") .setTypedConfig(Any.pack(StringValue.of("string value"))) .build(); - assertThat(XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, true) + assertThat(XdsListenerResource + .parseHttpFilter(httpFilter, filterRegistry, true, getXdsResourceTypeArgs(true)) .getErrorDetail()).isEqualTo( "HttpFilter [unsupported.filter]" + "(type.googleapis.com/google.protobuf.StringValue) is required but unsupported " @@ -1385,7 +1391,8 @@ public void parseHttpFilter_routerFilterForClient() { .setTypedConfig(Any.pack(Router.getDefaultInstance())) .build(); FilterConfig config = XdsListenerResource.parseHttpFilter( - httpFilter, filterRegistry, true /* isForClient */).getStruct(); + httpFilter, filterRegistry, true /* isForClient */, getXdsResourceTypeArgs(true)) + .getStruct(); assertThat(config.typeUrl()).isEqualTo(RouterFilter.TYPE_URL); } @@ -1399,7 +1406,8 @@ public void parseHttpFilter_routerFilterForServer() { .setTypedConfig(Any.pack(Router.getDefaultInstance())) .build(); FilterConfig config = XdsListenerResource.parseHttpFilter( - httpFilter, filterRegistry, false /* isForClient */).getStruct(); + httpFilter, filterRegistry, false /* isForClient */, getXdsResourceTypeArgs(false)) + .getStruct(); assertThat(config.typeUrl()).isEqualTo(RouterFilter.TYPE_URL); } @@ -1426,7 +1434,8 @@ public void parseHttpFilter_faultConfigForClient() { .build())) .build(); FilterConfig config = XdsListenerResource.parseHttpFilter( - httpFilter, filterRegistry, true /* isForClient */).getStruct(); + httpFilter, filterRegistry, true /* isForClient */, getXdsResourceTypeArgs(true)) + .getStruct(); assertThat(config).isInstanceOf(FaultConfig.class); } @@ -1453,7 +1462,8 @@ public void parseHttpFilter_faultConfigUnsupportedForServer() { .build())) .build(); StructOrError config = - XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, false /* isForClient */); + XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, false /* isForClient */, + getXdsResourceTypeArgs(false)); assertThat(config.getErrorDetail()).isEqualTo( "HttpFilter [envoy.fault](" + FaultFilter.TYPE_URL + ") is required but " + "unsupported for server"); @@ -1482,7 +1492,8 @@ public void parseHttpFilter_rbacConfigForServer() { .build())) .build(); FilterConfig config = XdsListenerResource.parseHttpFilter( - httpFilter, filterRegistry, false /* isForClient */).getStruct(); + httpFilter, filterRegistry, false /* isForClient */, getXdsResourceTypeArgs(false)) + .getStruct(); assertThat(config).isInstanceOf(RbacConfig.class); } @@ -1509,7 +1520,8 @@ public void parseHttpFilter_rbacConfigUnsupportedForClient() { .build())) .build(); StructOrError config = - XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, true /* isForClient */); + XdsListenerResource.parseHttpFilter(httpFilter, filterRegistry, true /* isForClient */, + getXdsResourceTypeArgs(true)); assertThat(config.getErrorDetail()).isEqualTo( "HttpFilter [envoy.auth](" + RbacFilter.TYPE_URL + ") is required but " + "unsupported for client"); @@ -1534,7 +1546,8 @@ public void parseOverrideRbacFilterConfig() { .build(); Map configOverrides = ImmutableMap.of("envoy.auth", Any.pack(rbacPerRoute)); Map parsedConfigs = - XdsRouteConfigureResource.parseOverrideFilterConfigs(configOverrides, filterRegistry) + XdsRouteConfigureResource.parseOverrideFilterConfigs(configOverrides, filterRegistry, + getXdsResourceTypeArgs(true)) .getStruct(); assertThat(parsedConfigs).hasSize(1); assertThat(parsedConfigs).containsKey("envoy.auth"); @@ -1555,7 +1568,8 @@ public void parseOverrideFilterConfigs_unsupportedButOptional() { .setIsOptional(true).setConfig(Any.pack(StringValue.of("string value"))) .build())); Map parsedConfigs = - XdsRouteConfigureResource.parseOverrideFilterConfigs(configOverrides, filterRegistry) + XdsRouteConfigureResource.parseOverrideFilterConfigs(configOverrides, filterRegistry, + getXdsResourceTypeArgs(true)) .getStruct(); assertThat(parsedConfigs).hasSize(1); assertThat(parsedConfigs).containsKey("envoy.fault"); @@ -1574,7 +1588,9 @@ public void parseOverrideFilterConfigs_unsupportedAndRequired() { Any.pack(io.envoyproxy.envoy.config.route.v3.FilterConfig.newBuilder() .setIsOptional(false).setConfig(Any.pack(StringValue.of("string value"))) .build())); - assertThat(XdsRouteConfigureResource.parseOverrideFilterConfigs(configOverrides, filterRegistry) + assertThat(XdsRouteConfigureResource + .parseOverrideFilterConfigs(configOverrides, filterRegistry, + getXdsResourceTypeArgs(true)) .getErrorDetail()).isEqualTo( "HttpFilter [unsupported.filter]" + "(type.googleapis.com/google.protobuf.StringValue) is required but unsupported"); @@ -1584,7 +1600,9 @@ public void parseOverrideFilterConfigs_unsupportedAndRequired() { Any.pack(httpFault), "unsupported.filter", Any.pack(StringValue.of("string value"))); - assertThat(XdsRouteConfigureResource.parseOverrideFilterConfigs(configOverrides, filterRegistry) + assertThat(XdsRouteConfigureResource + .parseOverrideFilterConfigs(configOverrides, filterRegistry, + getXdsResourceTypeArgs(true)) .getErrorDetail()).isEqualTo( "HttpFilter [unsupported.filter]" + "(type.googleapis.com/google.protobuf.StringValue) is required but unsupported"); @@ -3614,7 +3632,7 @@ private static Filter buildHttpConnectionManagerFilter(HttpFilter... httpFilters private XdsResourceType.Args getXdsResourceTypeArgs(boolean isTrustedServer) { return new XdsResourceType.Args( - ServerInfo.create("http://td", "", false, isTrustedServer, false, false), "1.0", null, null, null, null + ServerInfo.create("http://td", "", false, isTrustedServer, false, false), "1.0", null, XdsTestUtils.EMPTY_BOOTSTRAP, null, null ); } } diff --git a/xds/src/test/java/io/grpc/xds/RbacFilterTest.java b/xds/src/test/java/io/grpc/xds/RbacFilterTest.java index 334e159dd1d..1dd0d93b119 100644 --- a/xds/src/test/java/io/grpc/xds/RbacFilterTest.java +++ b/xds/src/test/java/io/grpc/xds/RbacFilterTest.java @@ -54,6 +54,9 @@ import io.grpc.Status; import io.grpc.testing.TestMethodDescriptors; import io.grpc.xds.Filter.FilterConfig; +import io.grpc.xds.client.Bootstrapper.BootstrapInfo; +import io.grpc.xds.client.Bootstrapper.ServerInfo; +import io.grpc.xds.client.EnvoyProtoData.Node; import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine; import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AlwaysTrueMatcher; import io.grpc.xds.internal.rbac.engine.GrpcAuthorizationEngine.AuthConfig; @@ -120,7 +123,7 @@ public void ipPortParser() { } @Test - @SuppressWarnings({"unchecked", "deprecation"}) + @SuppressWarnings("unchecked") public void portRangeParser() { List permissionList = Arrays.asList( Permission.newBuilder().setDestinationPortRange( @@ -299,7 +302,7 @@ public void handleException() { .putPolicies("policy-name", Policy.newBuilder().setCondition(Expr.newBuilder().build()).build()) .build()).build(); - result = FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto)); + result = FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto), getFilterContext()); assertThat(result.errorDetail).isNotNull(); } @@ -321,7 +324,8 @@ public void overrideConfig() { RbacConfig original = RbacConfig.create(authconfig); RBACPerRoute rbacPerRoute = RBACPerRoute.newBuilder().build(); - RbacConfig override = FILTER_PROVIDER.parseFilterConfigOverride(Any.pack(rbacPerRoute)).config; + RbacConfig override = FILTER_PROVIDER.parseFilterConfigOverride(Any.pack(rbacPerRoute), + getFilterContext()).config; assertThat(override).isEqualTo(RbacConfig.create(null)); ServerInterceptor interceptor = FILTER_PROVIDER.newInstance(name).buildServerInterceptor(original, override); @@ -346,22 +350,26 @@ public void ignoredConfig() { Message rawProto = io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC.newBuilder() .setRules(RBAC.newBuilder().setAction(Action.LOG) .putPolicies("policy-name", Policy.newBuilder().build()).build()).build(); - ConfigOrError result = FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto)); + ConfigOrError result = + FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto), getFilterContext()); assertThat(result.config).isEqualTo(RbacConfig.create(null)); } @Test public void testOrderIndependenceOfPolicies() { Message rawProto = buildComplexRbac(ImmutableList.of(1, 2, 3, 4, 5, 6), true); - ConfigOrError ascFirst = FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto)); + ConfigOrError ascFirst = + FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto), getFilterContext()); rawProto = buildComplexRbac(ImmutableList.of(1, 2, 3, 4, 5, 6), false); - ConfigOrError ascLast = FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto)); + ConfigOrError ascLast = + FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto), getFilterContext()); assertThat(ascFirst.config).isEqualTo(ascLast.config); rawProto = buildComplexRbac(ImmutableList.of(6, 5, 4, 3, 2, 1), true); - ConfigOrError decFirst = FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto)); + ConfigOrError decFirst = + FILTER_PROVIDER.parseFilterConfig(Any.pack(rawProto), getFilterContext()); assertThat(ascFirst.config).isEqualTo(decFirst.config); } @@ -390,7 +398,7 @@ private ConfigOrError parseRaw(List permissionList, List principalList) { Message rawProto = buildRbac(permissionList, principalList); Any proto = Any.pack(rawProto); - return FILTER_PROVIDER.parseFilterConfig(proto); + return FILTER_PROVIDER.parseFilterConfig(proto, getFilterContext()); } private io.envoyproxy.envoy.extensions.filters.http.rbac.v3.RBAC buildRbac( @@ -458,6 +466,19 @@ private ConfigOrError parseOverride(List permissionList, RBACPerRoute rbacPerRoute = RBACPerRoute.newBuilder().setRbac( buildRbac(permissionList, principalList)).build(); Any proto = Any.pack(rbacPerRoute); - return FILTER_PROVIDER.parseFilterConfigOverride(proto); + return FILTER_PROVIDER.parseFilterConfigOverride(proto, getFilterContext()); + } + + private Filter.FilterContext getFilterContext() { + return Filter.FilterContext.builder() + .bootstrapInfo(BootstrapInfo.builder() + .servers(Collections.singletonList( + ServerInfo.create( + "test_target", Collections.emptyMap()))) + .node(Node.newBuilder().build()) + .build()) + .serverInfo(ServerInfo.create( + "test_target", Collections.emptyMap(), false, true, false, false)) + .build(); } } diff --git a/xds/src/test/java/io/grpc/xds/StatefulFilter.java b/xds/src/test/java/io/grpc/xds/StatefulFilter.java index 4ef662c7ccd..7626222dc04 100644 --- a/xds/src/test/java/io/grpc/xds/StatefulFilter.java +++ b/xds/src/test/java/io/grpc/xds/StatefulFilter.java @@ -128,12 +128,13 @@ public synchronized int getCount() { } @Override - public ConfigOrError parseFilterConfig(Message rawProtoMessage) { + public ConfigOrError parseFilterConfig(Message rawProtoMessage, FilterContext context) { return ConfigOrError.fromConfig(Config.fromProto(rawProtoMessage, typeUrl)); } @Override - public ConfigOrError parseFilterConfigOverride(Message rawProtoMessage) { + public ConfigOrError parseFilterConfigOverride( + Message rawProtoMessage, FilterContext context) { return ConfigOrError.fromConfig(Config.fromProto(rawProtoMessage, typeUrl)); } } diff --git a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java index f81957ee311..93113411b5e 100644 --- a/xds/src/test/java/io/grpc/xds/XdsTestUtils.java +++ b/xds/src/test/java/io/grpc/xds/XdsTestUtils.java @@ -88,6 +88,11 @@ public class XdsTestUtils { static final Bootstrapper.ServerInfo EMPTY_BOOTSTRAPPER_SERVER_INFO = Bootstrapper.ServerInfo.create( "td.googleapis.com", InsecureChannelCredentials.create(), false, true, false, false); + static final Bootstrapper.BootstrapInfo EMPTY_BOOTSTRAP = + Bootstrapper.BootstrapInfo.builder() + .servers(com.google.common.collect.ImmutableList.of(EMPTY_BOOTSTRAPPER_SERVER_INFO)) + .node(io.grpc.xds.client.EnvoyProtoData.Node.newBuilder().setId("node-id").build()) + .build(); public static final String ENDPOINT_HOSTNAME = "data-host"; public static final int ENDPOINT_PORT = 1234; @@ -252,7 +257,7 @@ static XdsConfig getDefaultXdsConfig(String serverHostName) RouteConfiguration routeConfiguration = buildRouteConfiguration(serverHostName, RDS_NAME, CLUSTER_NAME); XdsResourceType.Args args = new XdsResourceType.Args( - EMPTY_BOOTSTRAPPER_SERVER_INFO, "0", "0", null, null, null); + EMPTY_BOOTSTRAPPER_SERVER_INFO, "0", "0", EMPTY_BOOTSTRAP, null, null); XdsRouteConfigureResource.RdsUpdate rdsUpdate = XdsRouteConfigureResource.getInstance().doParse(args, routeConfiguration);