Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

xds: Nack xds response when weighted cluster total weight sums zero #9738

Merged
merged 1 commit into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,7 @@ static StructOrError<RouteAction> parseRouteAction(
return StructOrError.fromError("No cluster found in weighted cluster list");
}
List<ClusterWeight> weightedClusters = new ArrayList<>();
int clusterWeightSum = 0;
for (io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight clusterWeight
: clusterWeights) {
StructOrError<ClusterWeight> clusterWeightOrError =
Expand All @@ -519,8 +520,12 @@ static StructOrError<RouteAction> parseRouteAction(
return StructOrError.fromError("RouteAction contains invalid ClusterWeight: "
+ clusterWeightOrError.getErrorDetail());
}
clusterWeightSum += clusterWeight.getWeight().getValue();
weightedClusters.add(clusterWeightOrError.getStruct());
}
if (clusterWeightSum <= 0) {
return StructOrError.fromError("Sum of cluster weights should be above 0.");
}
return StructOrError.fromStruct(VirtualHost.Route.RouteAction.forWeightedClusters(
weightedClusters, hashPolicies, timeoutNano, retryPolicy));
case CLUSTER_SPECIFIER_PLUGIN:
Expand Down
22 changes: 22 additions & 0 deletions xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,28 @@ public void parseRouteAction_withWeightedCluster() {
ClusterWeight.create("cluster-bar", 70, ImmutableMap.<String, FilterConfig>of()));
}

@Test
public void parseRouteAction_weightedClusterSum() {
io.envoyproxy.envoy.config.route.v3.RouteAction proto =
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
.setWeightedClusters(
WeightedCluster.newBuilder()
.addClusters(
WeightedCluster.ClusterWeight
.newBuilder()
.setName("cluster-foo")
.setWeight(UInt32Value.newBuilder().setValue(0)))
.addClusters(WeightedCluster.ClusterWeight
.newBuilder()
.setName("cluster-bar")
.setWeight(UInt32Value.newBuilder().setValue(0))))
.build();
StructOrError<RouteAction> struct =
XdsRouteConfigureResource.parseRouteAction(proto, filterRegistry, false,
ImmutableMap.of(), ImmutableSet.of());
assertThat(struct.getErrorDetail()).isEqualTo("Sum of cluster weights should be above 0.");
}

@Test
public void parseRouteAction_withTimeoutByGrpcTimeoutHeaderMax() {
io.envoyproxy.envoy.config.route.v3.RouteAction proto =
Expand Down
46 changes: 46 additions & 0 deletions xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.google.protobuf.util.Durations;
import io.envoyproxy.envoy.config.cluster.v3.OutlierDetection;
import io.envoyproxy.envoy.config.route.v3.FilterConfig;
import io.envoyproxy.envoy.config.route.v3.WeightedCluster;
import io.envoyproxy.envoy.extensions.filters.http.router.v3.Router;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateProviderPluginInstance;
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CommonTlsContext;
Expand Down Expand Up @@ -1363,6 +1364,51 @@ public void rdsResponseErrorHandling_someResourcesFailedUnpack() {
verify(rdsResourceWatcher).onChanged(any(RdsUpdate.class));
}

@Test
public void rdsResponseErrorHandling_nackWeightedSumZero() {
DiscoveryRpcCall call = startResourceWatcher(XdsRouteConfigureResource.getInstance(),
RDS_RESOURCE, rdsResourceWatcher);
verifyResourceMetadataRequested(RDS, RDS_RESOURCE);

io.envoyproxy.envoy.config.route.v3.RouteAction routeAction =
io.envoyproxy.envoy.config.route.v3.RouteAction.newBuilder()
.setWeightedClusters(
WeightedCluster.newBuilder()
.addClusters(
WeightedCluster.ClusterWeight
.newBuilder()
.setName("cluster-foo")
.setWeight(UInt32Value.newBuilder().setValue(0)))
.addClusters(WeightedCluster.ClusterWeight
.newBuilder()
.setName("cluster-bar")
.setWeight(UInt32Value.newBuilder().setValue(0))))
.build();
io.envoyproxy.envoy.config.route.v3.Route route =
io.envoyproxy.envoy.config.route.v3.Route.newBuilder()
.setName("route-blade")
.setMatch(
io.envoyproxy.envoy.config.route.v3.RouteMatch.newBuilder()
.setPath("/service/method"))
.setRoute(routeAction)
.build();

Any zeroWeightSum = Any.pack(mf.buildRouteConfiguration(RDS_RESOURCE,
Arrays.asList(mf.buildVirtualHost(Arrays.asList(route), ImmutableMap.of()))));
List<Any> resources = ImmutableList.of(zeroWeightSum);
call.sendResponse(RDS, resources, VERSION_1, "0000");

List<String> errors = ImmutableList.of(
"RDS response RouteConfiguration \'route-configuration.googleapis.com\' validation error: "
+ "RouteConfiguration contains invalid virtual host: Virtual host [do not care] "
+ "contains invalid route : Route [route-blade] contains invalid RouteAction: "
+ "Sum of cluster weights should be above 0.");
verifySubscribedResourcesMetadataSizes(0, 0, 1, 0);
// The response is NACKed with the same error message.
call.verifyRequestNack(RDS, RDS_RESOURCE, "", "0000", NODE, errors);
verify(rdsResourceWatcher, never()).onChanged(any(RdsUpdate.class));
}

/**
* Tests a subscribed RDS resource transitioned to and from the invalid state.
*
Expand Down