From ed5072e1481c2f355e4f8b2e3eab92f1a7a7b7cd Mon Sep 17 00:00:00 2001 From: Kannan J Date: Tue, 20 May 2025 07:19:41 +0000 Subject: [PATCH 01/24] Add Docker fiels for xds example server and client. --- examples/example-xds/xds-client.Dockerfile | 47 ++++++++++++++++++++++ examples/example-xds/xds-server.Dockerfile | 47 ++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 examples/example-xds/xds-client.Dockerfile create mode 100644 examples/example-xds/xds-server.Dockerfile diff --git a/examples/example-xds/xds-client.Dockerfile b/examples/example-xds/xds-client.Dockerfile new file mode 100644 index 00000000000..0f34d219177 --- /dev/null +++ b/examples/example-xds/xds-client.Dockerfile @@ -0,0 +1,47 @@ +# Copyright 2024 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. + +# +# Stage 1: Build XDS client +# + +FROM eclipse-temurin:11-jdk AS build + +WORKDIR /grpc-java/examples +COPY . . + +RUN cd example-xds && ../gradlew installDist -PskipCodegen=true -PskipAndroid=true + +# +# Stage 2: +# +# - Copy only the necessary files to reduce Docker image size. +# - Have an ENTRYPOINT script which will launch the XDS client +# with the given parameters. +# + +FROM eclipse-temurin:11-jre + +WORKDIR /grpc-java/ +COPY --from=build /grpc-java/examples/example-xds/build/install/example-xds/. . + +# Intentionally after the COPY to force the update on each build. +# Update Ubuntu system packages: +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y autoremove \ + && rm -rf /var/lib/apt/lists/* + +# Client +ENTRYPOINT ["bin/xds-hello-world-client"] diff --git a/examples/example-xds/xds-server.Dockerfile b/examples/example-xds/xds-server.Dockerfile new file mode 100644 index 00000000000..542fb0263af --- /dev/null +++ b/examples/example-xds/xds-server.Dockerfile @@ -0,0 +1,47 @@ +# Copyright 2024 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. + +# +# Stage 1: Build XDS server +# + +FROM eclipse-temurin:11-jdk AS build + +WORKDIR /grpc-java/examples +COPY . . + +RUN cd example-xds && ../gradlew installDist -PskipCodegen=true -PskipAndroid=true + +# +# Stage 2: +# +# - Copy only the necessary files to reduce Docker image size. +# - Have an ENTRYPOINT script which will launch the XDS server +# with the given parameters. +# + +FROM eclipse-temurin:11-jre + +WORKDIR /grpc-java/ +COPY --from=build /grpc-java/examples/example-xds/build/install/example-xds/. . + +# Intentionally after the COPY to force the update on each build. +# Update Ubuntu system packages: +RUN apt-get update \ + && apt-get -y upgrade \ + && apt-get -y autoremove \ + && rm -rf /var/lib/apt/lists/* + +# Server +ENTRYPOINT ["bin/xds-hello-world-server"] From 459208c1844c25acb92ab05b112a2d03141ce70d Mon Sep 17 00:00:00 2001 From: deadEternally Date: Mon, 23 Jun 2025 17:20:37 +0530 Subject: [PATCH 02/24] in-progress changes. --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index c50f844d388..8cc48f65d67 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -157,14 +157,19 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { return fail(noneFoundError); } - // The LB policy config is provided in service_config.proto/JSON format. - NameResolver.ConfigOrError configOrError = - GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig( - Arrays.asList(clusterConfig.getClusterResource().lbPolicyConfig()), lbRegistry); - if (configOrError.getError() != null) { - // Should be impossible, because XdsClusterResource validated this - return fail(Status.INTERNAL.withDescription( - errorPrefix() + "Unable to parse the LB config: " + configOrError.getError())); + NameResolver.ConfigOrError configOrError; + if (clusterConfig.getChildren() instanceof EndpointConfig) { + // The LB policy config is provided in service_config.proto/JSON format. + configOrError = + GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig( + Arrays.asList(clusterConfig.getClusterResource().lbPolicyConfig()), lbRegistry); + if (configOrError.getError() != null) { + // Should be impossible, because XdsClusterResource validated this + return fail(Status.INTERNAL.withDescription( + errorPrefix() + "Unable to parse the LB config: " + configOrError.getError())); + } + } else { + } ClusterResolverConfig config = new ClusterResolverConfig( From 6cddc61d2eef67d5d016850601a9b50197602140 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Tue, 24 Jun 2025 17:09:02 +0530 Subject: [PATCH 03/24] in-progress changes. --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 130 +++++++++--------- .../grpc/xds/ClusterResolverLoadBalancer.java | 29 ++-- .../ClusterResolverLoadBalancerProvider.java | 16 +-- .../io/grpc/xds/CdsLoadBalancer2Test.java | 14 +- .../xds/ClusterResolverLoadBalancerTest.java | 8 +- 5 files changed, 97 insertions(+), 100 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index 8cc48f65d67..9abbd022690 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -19,16 +19,21 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.grpc.ConnectivityState.TRANSIENT_FAILURE; import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; +import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; +import static java.util.Objects.requireNonNull; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CheckReturnValue; import io.grpc.InternalLogId; import io.grpc.LoadBalancer; +import io.grpc.LoadBalancerProvider; import io.grpc.LoadBalancerRegistry; import io.grpc.NameResolver; import io.grpc.Status; import io.grpc.StatusOr; +import io.grpc.xds.PriorityLoadBalancerProvider; +import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig; import io.grpc.util.GracefulSwitchLoadBalancer; import io.grpc.xds.CdsLoadBalancerProvider.CdsConfig; import io.grpc.xds.ClusterResolverLoadBalancerProvider.ClusterResolverConfig; @@ -44,7 +49,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Objects; /** * Load balancer for cds_experimental LB policy. One instance per top-level cluster. @@ -91,7 +99,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { if (clusterSubscription == null) { // Should be impossible, because XdsDependencyManager wouldn't have generated this return fail(Status.INTERNAL.withDescription( - errorPrefix() + "Unable to find non-dynamic root cluster")); + errorPrefix() + "Unable to find non-dynamic cluster")); } // The dynamic cluster must not have loaded yet return Status.OK; @@ -100,64 +108,9 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { return fail(clusterConfigOr.getStatus()); } XdsClusterConfig clusterConfig = clusterConfigOr.getValue(); - List leafNames; - if (clusterConfig.getChildren() instanceof AggregateConfig) { - leafNames = ((AggregateConfig) clusterConfig.getChildren()).getLeafNames(); - } else if (clusterConfig.getChildren() instanceof EndpointConfig) { - leafNames = ImmutableList.of(clusterName); - } else { - return fail(Status.INTERNAL.withDescription( - errorPrefix() + "Unexpected cluster children type: " - + clusterConfig.getChildren().getClass())); - } - if (leafNames.isEmpty()) { - // Should be impossible, because XdsClusterResource validated this - return fail(Status.UNAVAILABLE.withDescription( - errorPrefix() + "Zero leaf clusters for root cluster " + clusterName)); - } - - Status noneFoundError = Status.INTERNAL - .withDescription(errorPrefix() + "No leaves and no error; this is a bug"); - List instances = new ArrayList<>(); - for (String leafName : leafNames) { - StatusOr leafConfigOr = xdsConfig.getClusters().get(leafName); - if (!leafConfigOr.hasValue()) { - noneFoundError = leafConfigOr.getStatus(); - continue; - } - if (!(leafConfigOr.getValue().getChildren() instanceof EndpointConfig)) { - noneFoundError = Status.INTERNAL.withDescription( - errorPrefix() + "Unexpected child " + leafName + " cluster children type: " - + leafConfigOr.getValue().getChildren().getClass()); - continue; - } - CdsUpdate result = leafConfigOr.getValue().getClusterResource(); - DiscoveryMechanism instance; - if (result.clusterType() == ClusterType.EDS) { - instance = DiscoveryMechanism.forEds( - leafName, - result.edsServiceName(), - result.lrsServerInfo(), - result.maxConcurrentRequests(), - result.upstreamTlsContext(), - result.filterMetadata(), - result.outlierDetection()); - } else { - instance = DiscoveryMechanism.forLogicalDns( - leafName, - result.dnsHostName(), - result.lrsServerInfo(), - result.maxConcurrentRequests(), - result.upstreamTlsContext(), - result.filterMetadata()); - } - instances.add(instance); - } - if (instances.isEmpty()) { - return fail(noneFoundError); - } NameResolver.ConfigOrError configOrError; + Object childConfig; if (clusterConfig.getChildren() instanceof EndpointConfig) { // The LB policy config is provided in service_config.proto/JSON format. configOrError = @@ -168,19 +121,64 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { return fail(Status.INTERNAL.withDescription( errorPrefix() + "Unable to parse the LB config: " + configOrError.getError())); } + CdsUpdate result = clusterConfig.getClusterResource(); + DiscoveryMechanism instance; + if (result.clusterType() == ClusterType.EDS) { + instance = DiscoveryMechanism.forEds( + clusterName, + result.edsServiceName(), + result.lrsServerInfo(), + result.maxConcurrentRequests(), + result.upstreamTlsContext(), + result.filterMetadata(), + result.outlierDetection()); + } else { + instance = DiscoveryMechanism.forLogicalDns( + clusterName, + result.dnsHostName(), + result.lrsServerInfo(), + result.maxConcurrentRequests(), + result.upstreamTlsContext(), + result.filterMetadata()); + } + childConfig = new ClusterResolverConfig( + instance, + configOrError.getConfig(), + clusterConfig.getClusterResource().isHttp11ProxyAvailable()); + if (childLb == null) { + childLb = lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME).newLoadBalancer(helper); + } + } else if (clusterConfig.getChildren() instanceof AggregateConfig) { + LoadBalancerProvider priorityLbProvider = lbRegistry.getProvider(PRIORITY_POLICY_NAME); + if (childLb == null) { + childLb = priorityLbProvider.newLoadBalancer(helper); + } + Map priorityChildConfigs = new HashMap<>(); + for (String childCluster: requireNonNull(clusterConfig.getClusterResource().prioritizedClusterNames())) { + priorityChildConfigs.put(childCluster, new PriorityChildConfig( + GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( + priorityLbProvider, getCdsPolicyConfig(childCluster)), false)); + } + childConfig = new PriorityLoadBalancerProvider.PriorityLbConfig( + Collections.unmodifiableMap(priorityChildConfigs), + Collections.unmodifiableList( + requireNonNull(clusterConfig.getClusterResource().prioritizedClusterNames()))); } else { - + return fail(Status.INTERNAL.withDescription( + errorPrefix() + "Unexpected cluster children type: " + + clusterConfig.getChildren().getClass())); } - ClusterResolverConfig config = new ClusterResolverConfig( - Collections.unmodifiableList(instances), - configOrError.getConfig(), - clusterConfig.getClusterResource().isHttp11ProxyAvailable()); - if (childLb == null) { - childLb = lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME).newLoadBalancer(helper); - } return childLb.acceptResolvedAddresses( - resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(config).build()); + resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(childConfig).build()); + } + + private String getCdsPolicyConfig(String cluster) { + return String.format("{\n" + + " \"cds_experimental\": {\n" + + " \"cluster\": \"%s\"\n" + + " }\n" + + " }\n", cluster); } @Override diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java index 080760303bf..7ce75f93f73 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java @@ -185,21 +185,20 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { ClusterResolverConfig config = (ClusterResolverConfig) resolvedAddresses.getLoadBalancingPolicyConfig(); endpointLbConfig = config.lbConfig; - for (DiscoveryMechanism instance : config.discoveryMechanisms) { - clusters.add(instance.cluster); - ClusterState state; - if (instance.type == DiscoveryMechanism.Type.EDS) { - state = new EdsClusterState(instance.cluster, instance.edsServiceName, - instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext, - instance.filterMetadata, instance.outlierDetection); - } else { // logical DNS - state = new LogicalDnsClusterState(instance.cluster, instance.dnsHostName, - instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext, - instance.filterMetadata); - } - clusterStates.put(instance.cluster, state); - state.start(); - } + DiscoveryMechanism instance = config.discoveryMechanism; + clusters.add(instance.cluster); + ClusterState state; + if (instance.type == DiscoveryMechanism.Type.EDS) { + state = new EdsClusterState(instance.cluster, instance.edsServiceName, + instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext, + instance.filterMetadata, instance.outlierDetection); + } else { // logical DNS + state = new LogicalDnsClusterState(instance.cluster, instance.dnsHostName, + instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext, + instance.filterMetadata); + } + clusterStates.put(instance.cluster, state); + state.start(); return Status.OK; } diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java index b5dcb271368..40ae920fe41 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java @@ -70,15 +70,15 @@ public LoadBalancer newLoadBalancer(Helper helper) { } static final class ClusterResolverConfig { - // Ordered list of clusters to be resolved. - final List discoveryMechanisms; + // Clusters to be resolved. + final DiscoveryMechanism discoveryMechanism; // GracefulSwitch configuration final Object lbConfig; private final boolean isHttp11ProxyAvailable; - ClusterResolverConfig(List discoveryMechanisms, Object lbConfig, - boolean isHttp11ProxyAvailable) { - this.discoveryMechanisms = checkNotNull(discoveryMechanisms, "discoveryMechanisms"); + ClusterResolverConfig(DiscoveryMechanism discoveryMechanism, Object lbConfig, + boolean isHttp11ProxyAvailable) { + this.discoveryMechanism = checkNotNull(discoveryMechanism, "discoveryMechanism"); this.lbConfig = checkNotNull(lbConfig, "lbConfig"); this.isHttp11ProxyAvailable = isHttp11ProxyAvailable; } @@ -89,7 +89,7 @@ boolean isHttp11ProxyAvailable() { @Override public int hashCode() { - return Objects.hash(discoveryMechanisms, lbConfig); + return Objects.hash(discoveryMechanism, lbConfig); } @Override @@ -101,14 +101,14 @@ public boolean equals(Object o) { return false; } ClusterResolverConfig that = (ClusterResolverConfig) o; - return discoveryMechanisms.equals(that.discoveryMechanisms) + return discoveryMechanism.equals(that.discoveryMechanism) && lbConfig.equals(that.lbConfig); } @Override public String toString() { return MoreObjects.toStringHelper(this) - .add("discoveryMechanisms", discoveryMechanisms) + .add("discoveryMechanism", discoveryMechanism) .add("lbConfig", lbConfig) .toString(); } diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index 258e2909203..729c4a35afa 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -246,7 +246,7 @@ public void discoverTopLevelEdsCluster() { FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forEds( CLUSTER, EDS_SERVICE_NAME, lrsServerInfo, 100L, upstreamTlsContext, @@ -296,7 +296,7 @@ public void discoverTopLevelLogicalDnsCluster() { FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forLogicalDns( CLUSTER, "dns.example.com:1111", lrsServerInfo, 100L, upstreamTlsContext, @@ -332,7 +332,7 @@ public void nonAggregateCluster_resourceUpdate() { assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forEds( CLUSTER, EDS_SERVICE_NAME, null, 100L, null, Collections.emptyMap(), null))); @@ -348,7 +348,7 @@ public void nonAggregateCluster_resourceUpdate() { assertThat(childBalancers).hasSize(1); childBalancer = Iterables.getOnlyElement(childBalancers); childLbConfig = (ClusterResolverConfig) childBalancer.config; - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forEds( CLUSTER, EDS_SERVICE_NAME, null, 200L, null, Collections.emptyMap(), null))); @@ -363,7 +363,7 @@ public void nonAggregateCluster_resourceRevoked() { assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forEds( CLUSTER, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null))); @@ -395,7 +395,7 @@ public void dynamicCluster() { assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forEds( clusterName, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null))); @@ -462,7 +462,7 @@ public void discoverAggregateCluster() { assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; // Clusters are resolved recursively, later duplicates removed: [cluster3, cluster4, cluster2] - assertThat(childLbConfig.discoveryMechanisms).isEqualTo( + assertThat(childLbConfig.discoveryMechanism).isEqualTo( Arrays.asList( DiscoveryMechanism.forEds( cluster3, EDS_SERVICE_NAME, null, 100L, null, Collections.emptyMap(), null), diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index d701f281c01..09fefce2696 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -244,7 +244,7 @@ public void tearDown() { @Test public void edsClustersWithRingHashEndpointLbPolicy() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), ringHash, false); + edsDiscoveryMechanism1, ringHash, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); @@ -310,7 +310,7 @@ public void edsClustersWithRingHashEndpointLbPolicy() { @Test public void edsClustersWithLeastRequestEndpointLbPolicy() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), leastRequest, false); + edsDiscoveryMechanism1, leastRequest, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); @@ -357,7 +357,7 @@ public void edsClustersWithLeastRequestEndpointLbPolicy() { @Test public void edsClustersEndpointHostname_addedToAddressAttribute() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanismWithOutlierDetection), leastRequest, false); + edsDiscoveryMechanismWithOutlierDetection, leastRequest, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); @@ -431,7 +431,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { @Test public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanismWithOutlierDetection), leastRequest, true); + edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); From f038f4c7234945468fde88fbf811266793fcca26 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Wed, 25 Jun 2025 12:36:45 +0530 Subject: [PATCH 04/24] in-progress changes. --- .../xds/ClusterResolverLoadBalancerTest.java | 573 ++++++------------ 1 file changed, 177 insertions(+), 396 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index 09fefce2696..b4819d808c8 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -384,45 +384,45 @@ public void edsClustersEndpointHostname_addedToAddressAttribute() { @Test public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanismWithOutlierDetection), leastRequest, true); + edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); EquivalentAddressGroup endpoint = - new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); + new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); // Proxy address in endpointMetadata (use FakeSocketAddress directly) SocketAddress proxyAddress = new FakeSocketAddress("127.0.0.2"); ImmutableMap endpointMetadata = - ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); + ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); // No proxy in locality metadata ImmutableMap localityMetadata = ImmutableMap.of(); LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, - "hostname1", endpointMetadata)), - 100 /* localityWeight */, 1 /* priority */, localityMetadata); + Arrays.asList( + LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, + "hostname1", endpointMetadata)), + 100 /* localityWeight */, 1 /* priority */, localityMetadata); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints)); assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); // Get the rewritten address SocketAddress rewrittenAddress = - childBalancer.addresses.get(0).getAddresses().get(0); + childBalancer.addresses.get(0).getAddresses().get(0); assertThat(rewrittenAddress).isInstanceOf(HttpConnectProxiedSocketAddress.class); HttpConnectProxiedSocketAddress proxiedSocket = - (HttpConnectProxiedSocketAddress) rewrittenAddress; + (HttpConnectProxiedSocketAddress) rewrittenAddress; // Assert that the target address is the original address assertThat(proxiedSocket.getTargetAddress()) - .isEqualTo(endpoint.getAddresses().get(0)); + .isEqualTo(endpoint.getAddresses().get(0)); // Assert that the proxy address is correctly set assertThat(proxiedSocket.getProxyAddress()).isEqualTo(proxyAddress); @@ -431,13 +431,13 @@ public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { @Test public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); + edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); EquivalentAddressGroup endpoint = - new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.2", 8080)); + new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.2", 8080)); // No proxy in endpointMetadata ImmutableMap endpointMetadata = ImmutableMap.of(); @@ -445,17 +445,17 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { // Proxy address is now in localityMetadata SocketAddress proxyAddress = new FakeSocketAddress("proxy-addr"); ImmutableMap localityMetadata = - ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); + ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, - "hostname2", endpointMetadata)), - 100 /* localityWeight */, 1 /* priority */, localityMetadata); + Arrays.asList( + LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, + "hostname2", endpointMetadata)), + 100 /* localityWeight */, 1 /* priority */, localityMetadata); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints)); assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); @@ -466,7 +466,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { // Assert that the address was rewritten assertThat(rewrittenAddress).isInstanceOf(HttpConnectProxiedSocketAddress.class); HttpConnectProxiedSocketAddress proxiedSocket = - (HttpConnectProxiedSocketAddress) rewrittenAddress; + (HttpConnectProxiedSocketAddress) rewrittenAddress; // Assert that the target address is the original address assertThat(proxiedSocket.getTargetAddress()).isEqualTo(endpoint.getAddresses().get(0)); @@ -478,48 +478,36 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { @Test public void onlyEdsClusters_receivedEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, edsDiscoveryMechanism2), roundRobin, false); + edsDiscoveryMechanism2, roundRobin, false); deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1, EDS_SERVICE_NAME2); + assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME2); assertThat(childBalancers).isEmpty(); // CLUSTER1 has priority 1 (priority3), which has locality 2, which has endpoint3. // CLUSTER2 has priority 1 (priority1) and 2 (priority2); priority1 has locality1, // which has endpoint1 and endpoint2; priority2 has locality3, which has endpoint4. EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); - EquivalentAddressGroup endpoint3 = makeAddress("endpoint-addr-3"); EquivalentAddressGroup endpoint4 = makeAddress("endpoint-addr-4"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint1, 100, - true, "hostname1", ImmutableMap.of()), - LbEndpoint.create(endpoint2, 100, - true, "hostname1", ImmutableMap.of())), - 70 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); - LocalityLbEndpoints localityLbEndpoints2 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint3, 100, true, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Arrays.asList( + LbEndpoint.create(endpoint1, 100, + true, "hostname1", ImmutableMap.of()), + LbEndpoint.create(endpoint2, 100, + true, "hostname1", ImmutableMap.of())), + 70 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints3 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint4, 100, true, - "hostname3", ImmutableMap.of())), - 20 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint4, 100, true, + "hostname3", ImmutableMap.of())), + 20 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority1 = CLUSTER2 + "[child1]"; String priority2 = CLUSTER2 + "[child2]"; - String priority3 = CLUSTER1 + "[child1]"; // CLUSTER2: locality1 with priority 1 and locality3 with priority 2. xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME2, - ImmutableMap.of(locality1, localityLbEndpoints1, locality3, localityLbEndpoints3)); - assertThat(childBalancers).isEmpty(); // not created until all clusters resolved - - // CLUSTER1: locality2 with priority 1. - xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality2, localityLbEndpoints2)); + EDS_SERVICE_NAME2, + ImmutableMap.of(locality1, localityLbEndpoints1, locality3, localityLbEndpoints3)); // Endpoints of all clusters have been resolved. assertThat(childBalancers).hasSize(1); @@ -527,65 +515,56 @@ public void onlyEdsClusters_receivedEndpoints() { assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME); PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config; assertThat(priorityLbConfig.priorities) - .containsExactly(priority3, priority1, priority2).inOrder(); + .containsExactly(priority1, priority2).inOrder(); PriorityChildConfig priorityChildConfig1 = priorityLbConfig.childConfigs.get(priority1); assertThat(priorityChildConfig1.ignoreReresolution).isTrue(); assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig1.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); + .getPolicyName()) + .isEqualTo(CLUSTER_IMPL_POLICY_NAME); ClusterImplConfig clusterImplConfig1 = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig1.childConfig); assertClusterImplConfig(clusterImplConfig1, CLUSTER2, EDS_SERVICE_NAME2, LRS_SERVER_INFO, 200L, - tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); + tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); WrrLocalityConfig wrrLocalityConfig1 = (WrrLocalityConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); LoadBalancerProvider childProvider1 = - GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig1.childConfig); assertThat(childProvider1.getPolicyName()).isEqualTo("round_robin"); PriorityChildConfig priorityChildConfig2 = priorityLbConfig.childConfigs.get(priority2); assertThat(priorityChildConfig2.ignoreReresolution).isTrue(); assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig2.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); + .getPolicyName()) + .isEqualTo(CLUSTER_IMPL_POLICY_NAME); ClusterImplConfig clusterImplConfig2 = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig2.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig2.childConfig); assertClusterImplConfig(clusterImplConfig2, CLUSTER2, EDS_SERVICE_NAME2, LRS_SERVER_INFO, 200L, - tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); + tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); WrrLocalityConfig wrrLocalityConfig2 = (WrrLocalityConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); LoadBalancerProvider childProvider2 = - GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig2.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig2.childConfig); assertThat(childProvider2.getPolicyName()).isEqualTo("round_robin"); - PriorityChildConfig priorityChildConfig3 = priorityLbConfig.childConfigs.get(priority3); - assertThat(priorityChildConfig3.ignoreReresolution).isTrue(); - assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig3.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); - ClusterImplConfig clusterImplConfig3 = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig3.childConfig); - assertClusterImplConfig(clusterImplConfig3, CLUSTER1, EDS_SERVICE_NAME1, LRS_SERVER_INFO, 100L, - tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); WrrLocalityConfig wrrLocalityConfig3 = (WrrLocalityConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); LoadBalancerProvider childProvider3 = - GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig3.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig3.childConfig); assertThat(childProvider3.getPolicyName()).isEqualTo("round_robin"); for (EquivalentAddressGroup eag : childBalancer.addresses) { if (eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY) == locality1) { assertThat(eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY_WEIGHT)) - .isEqualTo(70); + .isEqualTo(70); } if (eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY) == locality2) { assertThat(eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY_WEIGHT)) - .isEqualTo(10); + .isEqualTo(10); } if (eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY) == locality3) { assertThat(eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY_WEIGHT)) - .isEqualTo(20); + .isEqualTo(20); } } } @@ -594,15 +573,15 @@ public void onlyEdsClusters_receivedEndpoints() { private void verifyEdsPriorityNames(List want, Map... updates) { ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism2), roundRobin, false); + edsDiscoveryMechanism2, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME2); assertThat(childBalancers).isEmpty(); for (Map update: updates) { xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME2, - update); + EDS_SERVICE_NAME2, + update); } assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); @@ -615,32 +594,32 @@ private void verifyEdsPriorityNames(List want, @SuppressWarnings("unchecked") public void edsUpdatePriorityName_twoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child1]", CLUSTER2 + "[child2]"), - ImmutableMap.of(locality1, createEndpoints(1), - locality2, createEndpoints(2) - )); + ImmutableMap.of(locality1, createEndpoints(1), + locality2, createEndpoints(2) + )); } @Test @SuppressWarnings("unchecked") public void edsUpdatePriorityName_addOnePriority() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child2]"), - ImmutableMap.of(locality1, createEndpoints(1)), - ImmutableMap.of(locality2, createEndpoints(1) - )); + ImmutableMap.of(locality1, createEndpoints(1)), + ImmutableMap.of(locality2, createEndpoints(1) + )); } @Test @SuppressWarnings("unchecked") public void edsUpdatePriorityName_swapTwoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child2]", CLUSTER2 + "[child1]", - CLUSTER2 + "[child3]"), - ImmutableMap.of(locality1, createEndpoints(1), - locality2, createEndpoints(2), - locality3, createEndpoints(3) - ), - ImmutableMap.of(locality1, createEndpoints(2), - locality2, createEndpoints(1), - locality3, createEndpoints(3)) + CLUSTER2 + "[child3]"), + ImmutableMap.of(locality1, createEndpoints(1), + locality2, createEndpoints(2), + locality3, createEndpoints(3) + ), + ImmutableMap.of(locality1, createEndpoints(2), + locality2, createEndpoints(1), + locality3, createEndpoints(3)) ); } @@ -648,102 +627,103 @@ locality3, createEndpoints(3)) @SuppressWarnings("unchecked") public void edsUpdatePriorityName_mergeTwoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child3]", CLUSTER2 + "[child1]"), - ImmutableMap.of(locality1, createEndpoints(1), - locality3, createEndpoints(3), - locality2, createEndpoints(2)), - ImmutableMap.of(locality1, createEndpoints(2), - locality3, createEndpoints(1), - locality2, createEndpoints(1) - )); + ImmutableMap.of(locality1, createEndpoints(1), + locality3, createEndpoints(3), + locality2, createEndpoints(2)), + ImmutableMap.of(locality1, createEndpoints(2), + locality3, createEndpoints(1), + locality2, createEndpoints(1) + )); } private LocalityLbEndpoints createEndpoints(int priority) { return LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(makeAddress("endpoint-addr-1"), 100, - true, "hostname1", ImmutableMap.of()), - LbEndpoint.create(makeAddress("endpoint-addr-2"), 100, - true, "hostname2", ImmutableMap.of())), - 70 /* localityWeight */, priority /* priority */, ImmutableMap.of()); + Arrays.asList( + LbEndpoint.create(makeAddress("endpoint-addr-1"), 100, + true, "hostname1", ImmutableMap.of()), + LbEndpoint.create(makeAddress("endpoint-addr-2"), 100, + true, "hostname2", ImmutableMap.of())), + 70 /* localityWeight */, priority /* priority */, ImmutableMap.of()); + } + + private void deliverLbConfig(ClusterResolverConfig config) { + loadBalancer.acceptResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(Collections.emptyList()) + .setAttributes( + // Other attributes not used by cluster_resolver LB are omitted. + Attributes.newBuilder() + .set(XdsAttributes.XDS_CLIENT_POOL, xdsClientPool) + .build()) + .setLoadBalancingPolicyConfig(config) + .build()); } @Test public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, edsDiscoveryMechanism2), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1, EDS_SERVICE_NAME2); + assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); reset(helper); xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); - verify(helper, never()).updateBalancingState( - any(ConnectivityState.class), any(SubchannelPicker.class)); // wait for CLUSTER2's results - xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME2); verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); assertPicker( - pickerCaptor.getValue(), - Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1, CLUSTER2)), - null); + pickerCaptor.getValue(), + Status.UNAVAILABLE.withDescription( + "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)), + null); } @Test - public void onlyEdsClusters_allResourcesRevoked_shutDownChildLbPolicy() { + public void edsCluster_allResourcesRevoked_shutDownChildLbPolicy() { ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, edsDiscoveryMechanism2), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1, EDS_SERVICE_NAME2); + assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); reset(helper); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); - EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, true, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); - LocalityLbEndpoints localityLbEndpoints2 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint2, 100, true, - "hostname2", ImmutableMap.of())), - 20 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, true, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints1)); - xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME2, Collections.singletonMap(locality2, localityLbEndpoints2)); + EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints1)); assertThat(childBalancers).hasSize(1); // child LB policy created FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - assertThat(((PriorityLbConfig) childBalancer.config).priorities).hasSize(2); - assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses); + assertThat(((PriorityLbConfig) childBalancer.config).priorities).hasSize(1); + assertAddressesEqual(Arrays.asList(endpoint1), childBalancer.addresses); xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME2); - xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); Status expectedError = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1, CLUSTER2)); + "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1, CLUSTER2)); assertPicker(pickerCaptor.getValue(), expectedError, null); } @Test public void handleEdsResource_ignoreUnhealthyEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of()), - LbEndpoint.create(endpoint2, 100, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Arrays.asList( + LbEndpoint.create(endpoint1, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of()), + LbEndpoint.create(endpoint2, 100, true /* isHealthy */, + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); + EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(childBalancer.addresses).hasSize(1); assertAddressesEqual(Collections.singletonList(endpoint2), childBalancer.addresses); @@ -752,23 +732,23 @@ public void handleEdsResource_ignoreUnhealthyEndpoints() { @Test public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints2 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint2, 100, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint2, 100, true /* isHealthy */, + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); for (EquivalentAddressGroup eag : childBalancer.addresses) { @@ -779,24 +759,24 @@ public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { @Test public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints2 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint2, 200, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint2, 200, true /* isHealthy */, + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority2 = CLUSTER1 + "[child2]"; xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(((PriorityLbConfig) childBalancer.config).priorities).containsExactly(priority2); @@ -805,25 +785,25 @@ public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { @Test public void handleEdsResource_noHealthyEndpoint() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint = makeAddress("endpoint-addr-1"); LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment(EDS_SERVICE_NAME1, - Collections.singletonMap(locality1, localityLbEndpoints)); // single endpoint, unhealthy + Collections.singletonMap(locality1, localityLbEndpoints)); // single endpoint, unhealthy assertThat(childBalancers).isEmpty(); verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); assertPicker( - pickerCaptor.getValue(), - Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Collections.singleton(CLUSTER1)), - null); + pickerCaptor.getValue(), + Status.UNAVAILABLE.withDescription( + "No usable endpoint from cluster(s): " + Collections.singleton(CLUSTER1)), + null); } @Test @@ -840,7 +820,7 @@ public void oldListenerCallback_onlyLogicalDnsCluster_endpointsResolved() { void do_onlyLogicalDnsCluster_endpointsResolved() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -856,23 +836,23 @@ void do_onlyLogicalDnsCluster_endpointsResolved() { PriorityChildConfig priorityChildConfig = priorityLbConfig.childConfigs.get(priority); assertThat(priorityChildConfig.ignoreReresolution).isFalse(); assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); + .getPolicyName()) + .isEqualTo(CLUSTER_IMPL_POLICY_NAME); ClusterImplConfig clusterImplConfig = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig.childConfig); assertClusterImplConfig(clusterImplConfig, CLUSTER_DNS, null, LRS_SERVER_INFO, 300L, null, - Collections.emptyList(), "pick_first"); + Collections.emptyList(), "pick_first"); assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses); assertThat(childBalancer.addresses.get(0).getAttributes() - .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); + .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); assertThat(childBalancer.addresses.get(1).getAttributes() - .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); + .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); } @Test public void onlyLogicalDnsCluster_handleRefreshNameResolution() { ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -901,7 +881,7 @@ void do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { InOrder inOrder = Mockito.inOrder(helper, backoffPolicyProvider, backoffPolicy1, backoffPolicy2); ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -947,7 +927,7 @@ void do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { public void onlyLogicalDnsCluster_refreshNameResolutionRaceWithResolutionError() { InOrder inOrder = Mockito.inOrder(backoffPolicyProvider, backoffPolicy1, backoffPolicy2); ClusterResolverConfig config = new ClusterResolverConfig( - Collections.singletonList(logicalDnsDiscoveryMechanism), roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -983,119 +963,22 @@ public void onlyLogicalDnsCluster_refreshNameResolutionRaceWithResolutionError() } @Test - public void edsClustersAndLogicalDnsCluster_receivedEndpoints() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); - assertThat(childBalancers).isEmpty(); - EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); // DNS endpoint - EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); // DNS endpoint - EquivalentAddressGroup endpoint3 = makeAddress("endpoint-addr-3"); // EDS endpoint - resolver.deliverEndpointAddresses(Arrays.asList(endpoint1, endpoint2)); - LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint3, 100, true, - "hostname3", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); - xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); - - assertThat(childBalancers).hasSize(1); - FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - assertThat(((PriorityLbConfig) childBalancer.config).priorities) - .containsExactly(CLUSTER1 + "[child1]", CLUSTER_DNS + "[child0]").inOrder(); - assertAddressesEqual(Arrays.asList(endpoint3, endpoint1, endpoint2), - childBalancer.addresses); // ordered by cluster then addresses - assertAddressesEqual(AddressFilter.filter(AddressFilter.filter( - childBalancer.addresses, CLUSTER1 + "[child1]"), - "{region=\"test-region-1\", zone=\"test-zone-1\", sub_zone=\"test-subzone-1\"}"), - Collections.singletonList(endpoint3)); - assertAddressesEqual(AddressFilter.filter(AddressFilter.filter( - childBalancer.addresses, CLUSTER_DNS + "[child0]"), - "{region=\"\", zone=\"\", sub_zone=\"\"}"), - Arrays.asList(endpoint1, endpoint2)); - } - - @Test - public void noEdsResourceExists_useDnsResolutionResults() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); - assertThat(childBalancers).isEmpty(); - reset(helper); - xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); - verify(helper, never()).updateBalancingState( - any(ConnectivityState.class), any(SubchannelPicker.class)); // wait for DNS results - - EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); - EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); - resolver.deliverEndpointAddresses(Arrays.asList(endpoint1, endpoint2)); - assertThat(childBalancers).hasSize(1); - FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - String priority = Iterables.getOnlyElement( - ((PriorityLbConfig) childBalancer.config).priorities); - assertThat(priority).isEqualTo(CLUSTER_DNS + "[child0]"); - assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses); - } - - @Test - public void edsResourceRevoked_dnsResolutionError_shutDownChildLbPolicyAndReturnErrorPicker() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); - assertThat(childBalancers).isEmpty(); - reset(helper); - EquivalentAddressGroup endpoint = makeAddress("endpoint-addr-1"); - LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint, 100, true, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); - xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); - resolver.deliverError(Status.UNKNOWN.withDescription("I am lost")); - assertThat(childBalancers).hasSize(1); - FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - assertThat(((PriorityLbConfig) childBalancer.config).priorities) - .containsExactly(CLUSTER1 + "[child1]"); - assertAddressesEqual(Collections.singletonList(endpoint), childBalancer.addresses); - assertThat(childBalancer.shutdown).isFalse(); - xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); - assertThat(childBalancer.shutdown).isTrue(); - verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); - assertPicker(pickerCaptor.getValue(), - Status.UNAVAILABLE.withDescription("I am lost"), null); - } - - @Test - public void resolutionErrorAfterChildLbCreated_propagateErrorIfAllClustersEncounterError() { + public void resolutionErrorAfterChildLbCreated_propagateError() { ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); reset(helper); EquivalentAddressGroup endpoint = makeAddress("endpoint-addr-1"); LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint, 100, true, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint, 100, true, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); - assertThat(childBalancers).isEmpty(); // not created until all clusters resolved. + EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); - resolver.deliverError(Status.UNKNOWN.withDescription("I am lost")); - - // DNS resolution failed, but there are EDS endpoints can be used. assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); // child LB created assertThat(childBalancer.upstreamError).isNull(); // should not propagate error to child LB @@ -1107,109 +990,7 @@ public void resolutionErrorAfterChildLbCreated_propagateErrorIfAllClustersEncoun assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("I am lost"); assertThat(childBalancer.shutdown).isFalse(); verify(helper, never()).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), any(SubchannelPicker.class)); - } - - @Test - public void resolutionErrorBeforeChildLbCreated_returnErrorPickerIfAllClustersEncounterError() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); - assertThat(childBalancers).isEmpty(); - reset(helper); - xdsClient.deliverError(Status.UNIMPLEMENTED.withDescription("not found")); - assertThat(childBalancers).isEmpty(); - verify(helper, never()).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), any(SubchannelPicker.class)); // wait for DNS - Status dnsError = Status.UNKNOWN.withDescription("I am lost"); - resolver.deliverError(dnsError); - verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); - assertPicker( - pickerCaptor.getValue(), - Status.UNAVAILABLE.withDescription(dnsError.getDescription()), - null); - } - - @Test - public void resolutionErrorBeforeChildLbCreated_edsOnly_returnErrorPicker() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - assertThat(childBalancers).isEmpty(); - reset(helper); - xdsClient.deliverError(Status.RESOURCE_EXHAUSTED.withDescription("OOM")); - assertThat(childBalancers).isEmpty(); - verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); - PickResult result = pickerCaptor.getValue().pickSubchannel(mock(PickSubchannelArgs.class)); - Status actualStatus = result.getStatus(); - assertThat(actualStatus.getCode()).isEqualTo(Status.Code.UNAVAILABLE); - assertThat(actualStatus.getDescription()).contains("RESOURCE_EXHAUSTED: OOM"); - } - - @Test - public void handleNameResolutionErrorFromUpstream_beforeChildLbCreated_returnErrorPicker() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - assertResolverCreated("/" + DNS_HOST_NAME); - assertThat(childBalancers).isEmpty(); - reset(helper); - Status upstreamError = Status.UNAVAILABLE.withDescription("unreachable"); - loadBalancer.handleNameResolutionError(upstreamError); - verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); - assertPicker(pickerCaptor.getValue(), upstreamError, null); - } - - @Test - public void handleNameResolutionErrorFromUpstream_afterChildLbCreated_fallThrough() { - ClusterResolverConfig config = new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false); - deliverLbConfig(config); - assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); - FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); - assertThat(childBalancers).isEmpty(); - reset(helper); - EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); - EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); - LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, true, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); - xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); - resolver.deliverEndpointAddresses(Collections.singletonList(endpoint2)); - assertThat(childBalancers).hasSize(1); - FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - assertThat(((PriorityLbConfig) childBalancer.config).priorities) - .containsExactly(CLUSTER1 + "[child1]", CLUSTER_DNS + "[child0]"); - assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses); - - loadBalancer.handleNameResolutionError(Status.UNAVAILABLE.withDescription("unreachable")); - assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE); - assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("unreachable"); - verify(helper, never()).updateBalancingState( - any(ConnectivityState.class), any(SubchannelPicker.class)); - } - - private void deliverLbConfig(ClusterResolverConfig config) { - loadBalancer.acceptResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes( - // Other attributes not used by cluster_resolver LB are omitted. - Attributes.newBuilder() - .set(XdsAttributes.XDS_CLIENT_POOL, xdsClientPool) - .build()) - .setLoadBalancingPolicyConfig(config) - .build()); + eq(ConnectivityState.TRANSIENT_FAILURE), any(SubchannelPicker.class)); } private FakeNameResolver assertResolverCreated(String uriPath) { From ad9b1b3ab88145e66cedbdce6eba1363f1126333 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Wed, 25 Jun 2025 16:55:55 +0530 Subject: [PATCH 05/24] in-progress changes. --- .../io/grpc/xds/CdsLoadBalancer2Test.java | 30 ++++++++----------- .../xds/ClusterResolverLoadBalancerTest.java | 10 +++---- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index 729c4a35afa..2a3bde25258 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -247,12 +247,11 @@ public void discoverTopLevelEdsCluster() { assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( - DiscoveryMechanism.forEds( - CLUSTER, EDS_SERVICE_NAME, lrsServerInfo, 100L, upstreamTlsContext, - Collections.emptyMap(), io.grpc.xds.EnvoyServerProtoData.OutlierDetection.create( - null, null, null, null, SuccessRateEjection.create(null, null, null, null), - FailurePercentageEjection.create(null, null, null, null))))); + DiscoveryMechanism.forEds( + CLUSTER, EDS_SERVICE_NAME, lrsServerInfo, 100L, upstreamTlsContext, + Collections.emptyMap(), io.grpc.xds.EnvoyServerProtoData.OutlierDetection.create( + null, null, null, null, SuccessRateEjection.create(null, null, null, null), + FailurePercentageEjection.create(null, null, null, null)))); assertThat( GracefulSwitchLoadBalancerAccessor.getChildProvider(childLbConfig.lbConfig).getPolicyName()) .isEqualTo("wrr_locality_experimental"); @@ -297,10 +296,9 @@ public void discoverTopLevelLogicalDnsCluster() { assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( - DiscoveryMechanism.forLogicalDns( - CLUSTER, "dns.example.com:1111", lrsServerInfo, 100L, upstreamTlsContext, - Collections.emptyMap()))); + DiscoveryMechanism.forLogicalDns( + CLUSTER, "dns.example.com:1111", lrsServerInfo, 100L, upstreamTlsContext, + Collections.emptyMap())); assertThat( GracefulSwitchLoadBalancerAccessor.getChildProvider(childLbConfig.lbConfig).getPolicyName()) .isEqualTo("wrr_locality_experimental"); @@ -333,9 +331,8 @@ public void nonAggregateCluster_resourceUpdate() { FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( DiscoveryMechanism.forEds( - CLUSTER, EDS_SERVICE_NAME, null, 100L, null, Collections.emptyMap(), null))); + CLUSTER, EDS_SERVICE_NAME, null, 100L, null, Collections.emptyMap(), null)); cluster = EDS_CLUSTER.toBuilder() .setCircuitBreakers(CircuitBreakers.newBuilder() @@ -349,9 +346,8 @@ public void nonAggregateCluster_resourceUpdate() { childBalancer = Iterables.getOnlyElement(childBalancers); childLbConfig = (ClusterResolverConfig) childBalancer.config; assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( DiscoveryMechanism.forEds( - CLUSTER, EDS_SERVICE_NAME, null, 200L, null, Collections.emptyMap(), null))); + CLUSTER, EDS_SERVICE_NAME, null, 200L, null, Collections.emptyMap(), null)); } @Test @@ -364,9 +360,8 @@ public void nonAggregateCluster_resourceRevoked() { FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( DiscoveryMechanism.forEds( - CLUSTER, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null))); + CLUSTER, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null)); controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of()); @@ -396,9 +391,8 @@ public void dynamicCluster() { FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( DiscoveryMechanism.forEds( - clusterName, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null))); + clusterName, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null)); assertThat(this.lastXdsConfig.getClusters()).containsKey(clusterName); shutdownLoadBalancer(); diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index b4819d808c8..ad3eb01f878 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -679,7 +679,7 @@ public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { } @Test - public void edsCluster_allResourcesRevoked_shutDownChildLbPolicy() { + public void edsCluster_resourcesRevoked_shutDownChildLbPolicy() { ClusterResolverConfig config = new ClusterResolverConfig( edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); @@ -699,11 +699,11 @@ public void edsCluster_allResourcesRevoked_shutDownChildLbPolicy() { assertThat(((PriorityLbConfig) childBalancer.config).priorities).hasSize(1); assertAddressesEqual(Arrays.asList(endpoint1), childBalancer.addresses); - xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME2); + xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); verify(helper).updateBalancingState( eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); Status expectedError = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1, CLUSTER2)); + "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)); assertPicker(pickerCaptor.getValue(), expectedError, null); } @@ -986,8 +986,8 @@ public void resolutionErrorAfterChildLbCreated_propagateError() { xdsClient.deliverError(Status.RESOURCE_EXHAUSTED.withDescription("out of memory")); assertThat(childBalancer.upstreamError).isNotNull(); // last cluster's (DNS) error propagated - assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNKNOWN); - assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("I am lost"); + assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE); + assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("Unable to load EDS backend-service-foo.googleapis.com. xDS server returned: RESOURCE_EXHAUSTED: out of memory"); assertThat(childBalancer.shutdown).isFalse(); verify(helper, never()).updateBalancingState( eq(ConnectivityState.TRANSIENT_FAILURE), any(SubchannelPicker.class)); From d92902d9bb1738a81c93170bda0721c14e877395 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Thu, 26 Jun 2025 17:24:33 +0530 Subject: [PATCH 06/24] in-progress changes. --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 18 ++--- .../io/grpc/xds/PriorityLoadBalancer.java | 2 +- .../io/grpc/xds/CdsLoadBalancer2Test.java | 66 +++++-------------- 3 files changed, 25 insertions(+), 61 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index 9abbd022690..10c6f3e32de 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.grpc.ConnectivityState.TRANSIENT_FAILURE; +import static io.grpc.xds.XdsLbPolicies.CDS_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; import static java.util.Objects.requireNonNull; @@ -155,9 +156,12 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { } Map priorityChildConfigs = new HashMap<>(); for (String childCluster: requireNonNull(clusterConfig.getClusterResource().prioritizedClusterNames())) { - priorityChildConfigs.put(childCluster, new PriorityChildConfig( - GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( - priorityLbProvider, getCdsPolicyConfig(childCluster)), false)); + priorityChildConfigs.put(childCluster, + new PriorityChildConfig( + GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( + lbRegistry.getProvider(CDS_POLICY_NAME), + new CdsConfig(childCluster)), + false)); } childConfig = new PriorityLoadBalancerProvider.PriorityLbConfig( Collections.unmodifiableMap(priorityChildConfigs), @@ -173,14 +177,6 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(childConfig).build()); } - private String getCdsPolicyConfig(String cluster) { - return String.format("{\n" + - " \"cds_experimental\": {\n" + - " \"cluster\": \"%s\"\n" + - " }\n" + - " }\n", cluster); - } - @Override public void handleNameResolutionError(Status error) { logger.log(XdsLogLevel.WARNING, "Received name resolution error: {0}", error); diff --git a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java index 845c167a643..f127ceb5fa0 100644 --- a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java @@ -88,7 +88,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { logger.log(XdsLogLevel.DEBUG, "Received resolution result: {0}", resolvedAddresses); this.resolvedAddresses = resolvedAddresses; PriorityLbConfig config = (PriorityLbConfig) resolvedAddresses.getLoadBalancingPolicyConfig(); - checkNotNull(config, "missing priority lb config"); + checkNotNull(config, "missing priority lb config"); priorityNames = config.priorities; priorityConfigs = config.childConfigs; Status status = Status.OK; diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index 2a3bde25258..e8a9e513ba6 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat; import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; +import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; import static io.grpc.xds.XdsTestControlPlaneService.ADS_TYPE_URL_CDS; import static io.grpc.xds.XdsTestControlPlaneService.ADS_TYPE_URL_EDS; import static io.grpc.xds.XdsTestControlPlaneService.ADS_TYPE_URL_LDS; @@ -27,6 +28,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import com.github.xds.type.v3.TypedStruct; import com.google.common.collect.ImmutableMap; @@ -150,6 +152,8 @@ public class CdsLoadBalancer2Test { @Before public void setUp() throws Exception { lbRegistry.register(new FakeLoadBalancerProvider(CLUSTER_RESOLVER_POLICY_NAME)); + lbRegistry.register(new PriorityLoadBalancerProvider()); + lbRegistry.register(new CdsLoadBalancerProvider()); lbRegistry.register(new FakeLoadBalancerProvider("round_robin")); lbRegistry.register( new FakeLoadBalancerProvider("ring_hash_experimental", new RingHashLoadBalancerProvider())); @@ -169,6 +173,8 @@ public void setUp() throws Exception { SynchronizationContext syncContext = new SynchronizationContext((t, e) -> { throw new AssertionError(e); }); + when(helper.getSynchronizationContext()).thenReturn(syncContext); + when(helper.getScheduledExecutorService()).thenReturn(fakeClock.getScheduledExecutorService()); NameResolver.Args nameResolverArgs = NameResolver.Args.newBuilder() .setDefaultPort(8080) @@ -403,10 +409,8 @@ public void dynamicCluster() { public void discoverAggregateCluster() { String cluster1 = "cluster-01.googleapis.com"; String cluster2 = "cluster-02.googleapis.com"; - String cluster3 = "cluster-03.googleapis.com"; - String cluster4 = "cluster-04.googleapis.com"; controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of( - // CLUSTER (aggr.) -> [cluster1 (aggr.), cluster2 (logical DNS), cluster3 (EDS)] + // cluster1 (aggr.) -> [cluster2 (EDS), cluster3 (EDS)] CLUSTER, Cluster.newBuilder() .setName(CLUSTER) .setClusterType(Cluster.CustomClusterType.newBuilder() @@ -414,59 +418,23 @@ public void discoverAggregateCluster() { .setTypedConfig(Any.pack(ClusterConfig.newBuilder() .addClusters(cluster1) .addClusters(cluster2) - .addClusters(cluster3) .build()))) - .setLbPolicy(Cluster.LbPolicy.RING_HASH) - .build(), - // cluster1 (aggr.) -> [cluster3 (EDS), cluster4 (EDS)] - cluster1, Cluster.newBuilder() - .setName(cluster1) - .setClusterType(Cluster.CustomClusterType.newBuilder() - .setName("envoy.clusters.aggregate") - .setTypedConfig(Any.pack(ClusterConfig.newBuilder() - .addClusters(cluster3) - .addClusters(cluster4) - .build()))) - .build(), - cluster2, Cluster.newBuilder() - .setName(cluster2) - .setType(Cluster.DiscoveryType.LOGICAL_DNS) - .setLoadAssignment(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .addLbEndpoints(LbEndpoint.newBuilder() - .setEndpoint(Endpoint.newBuilder() - .setAddress(Address.newBuilder() - .setSocketAddress(SocketAddress.newBuilder() - .setAddress("dns.example.com") - .setPortValue(1111))))))) .build(), - cluster3, EDS_CLUSTER.toBuilder() - .setName(cluster3) - .setCircuitBreakers(CircuitBreakers.newBuilder() - .addThresholds(CircuitBreakers.Thresholds.newBuilder() - .setPriority(RoutingPriority.DEFAULT) - .setMaxRequests(UInt32Value.newBuilder().setValue(100)))) - .build(), - cluster4, EDS_CLUSTER.toBuilder().setName(cluster4).build())); + cluster1, EDS_CLUSTER.toBuilder().setName(cluster1).build(), + cluster2, EDS_CLUSTER.toBuilder().setName(cluster2).build())); startXdsDepManager(); verify(helper, never()).updateBalancingState(eq(ConnectivityState.TRANSIENT_FAILURE), any()); assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); - assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME); - ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config; - // Clusters are resolved recursively, later duplicates removed: [cluster3, cluster4, cluster2] - assertThat(childLbConfig.discoveryMechanism).isEqualTo( - Arrays.asList( - DiscoveryMechanism.forEds( - cluster3, EDS_SERVICE_NAME, null, 100L, null, Collections.emptyMap(), null), - DiscoveryMechanism.forEds( - cluster4, EDS_SERVICE_NAME, null, null, null, Collections.emptyMap(), null), - DiscoveryMechanism.forLogicalDns( - cluster2, "dns.example.com:1111", null, null, null, Collections.emptyMap()))); - assertThat( - GracefulSwitchLoadBalancerAccessor.getChildProvider(childLbConfig.lbConfig).getPolicyName()) - .isEqualTo("ring_hash_experimental"); // dominated by top-level cluster's config + assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME); + PriorityLoadBalancerProvider.PriorityLbConfig childLbConfig = (PriorityLoadBalancerProvider.PriorityLbConfig) childBalancer.config; + assertThat(childLbConfig.priorities).hasSize(2); + assertThat(childLbConfig.priorities.get(0)).isEqualTo(cluster1); + assertThat(childLbConfig.priorities.get(1)).isEqualTo(cluster2); + assertThat(childLbConfig.childConfigs).hasSize(2); + PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig1 = childLbConfig.childConfigs.get(cluster2); + System.out.println(childConfig1); } @Test From 60fae376d5a76d23a05c28a7a3acef633cbb46e6 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Thu, 26 Jun 2025 18:35:16 +0530 Subject: [PATCH 07/24] in-progress changes. --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 17 ++++------ .../ClusterResolverLoadBalancerProvider.java | 1 - .../io/grpc/xds/PriorityLoadBalancer.java | 2 +- .../io/grpc/xds/CdsLoadBalancer2Test.java | 22 ++++++++++--- .../xds/ClusterResolverLoadBalancerTest.java | 32 +++++++++---------- 5 files changed, 41 insertions(+), 33 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index 10c6f3e32de..bbbab065db3 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -24,7 +24,6 @@ import static java.util.Objects.requireNonNull; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; import com.google.errorprone.annotations.CheckReturnValue; import io.grpc.InternalLogId; import io.grpc.LoadBalancer; @@ -33,12 +32,11 @@ import io.grpc.NameResolver; import io.grpc.Status; import io.grpc.StatusOr; -import io.grpc.xds.PriorityLoadBalancerProvider; -import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig; import io.grpc.util.GracefulSwitchLoadBalancer; import io.grpc.xds.CdsLoadBalancerProvider.CdsConfig; import io.grpc.xds.ClusterResolverLoadBalancerProvider.ClusterResolverConfig; import io.grpc.xds.ClusterResolverLoadBalancerProvider.ClusterResolverConfig.DiscoveryMechanism; +import io.grpc.xds.PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig; import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsClusterResource.CdsUpdate.ClusterType; import io.grpc.xds.XdsConfig.Subscription; @@ -47,13 +45,10 @@ import io.grpc.xds.XdsConfig.XdsClusterConfig.EndpointConfig; import io.grpc.xds.client.XdsLogger; import io.grpc.xds.client.XdsLogger.XdsLogLevel; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; -import java.util.Objects; /** * Load balancer for cds_experimental LB policy. One instance per top-level cluster. @@ -116,7 +111,8 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { // The LB policy config is provided in service_config.proto/JSON format. configOrError = GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig( - Arrays.asList(clusterConfig.getClusterResource().lbPolicyConfig()), lbRegistry); + Arrays.asList(clusterConfig.getClusterResource().lbPolicyConfig()), + lbRegistry); if (configOrError.getError() != null) { // Should be impossible, because XdsClusterResource validated this return fail(Status.INTERNAL.withDescription( @@ -155,7 +151,8 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { childLb = priorityLbProvider.newLoadBalancer(helper); } Map priorityChildConfigs = new HashMap<>(); - for (String childCluster: requireNonNull(clusterConfig.getClusterResource().prioritizedClusterNames())) { + for (String childCluster: requireNonNull( + clusterConfig.getClusterResource().prioritizedClusterNames())) { priorityChildConfigs.put(childCluster, new PriorityChildConfig( GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( @@ -165,8 +162,8 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { } childConfig = new PriorityLoadBalancerProvider.PriorityLbConfig( Collections.unmodifiableMap(priorityChildConfigs), - Collections.unmodifiableList( - requireNonNull(clusterConfig.getClusterResource().prioritizedClusterNames()))); + Collections.unmodifiableList(requireNonNull( + clusterConfig.getClusterResource().prioritizedClusterNames()))); } else { return fail(Status.INTERNAL.withDescription( errorPrefix() + "Unexpected cluster children type: " diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java index 40ae920fe41..7b8099664b1 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java @@ -30,7 +30,6 @@ import io.grpc.xds.EnvoyServerProtoData.OutlierDetection; import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; import io.grpc.xds.client.Bootstrapper.ServerInfo; -import java.util.List; import java.util.Map; import java.util.Objects; import javax.annotation.Nullable; diff --git a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java index f127ceb5fa0..845c167a643 100644 --- a/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/PriorityLoadBalancer.java @@ -88,7 +88,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { logger.log(XdsLogLevel.DEBUG, "Received resolution result: {0}", resolvedAddresses); this.resolvedAddresses = resolvedAddresses; PriorityLbConfig config = (PriorityLbConfig) resolvedAddresses.getLoadBalancingPolicyConfig(); - checkNotNull(config, "missing priority lb config"); + checkNotNull(config, "missing priority lb config"); priorityNames = config.priorities; priorityConfigs = config.childConfigs; Status status = Status.OK; diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index e8a9e513ba6..eeaba404679 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -17,6 +17,7 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; +import static io.grpc.xds.XdsLbPolicies.CDS_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; import static io.grpc.xds.XdsTestControlPlaneService.ADS_TYPE_URL_CDS; @@ -151,9 +152,9 @@ public class CdsLoadBalancer2Test { @Before public void setUp() throws Exception { + lbRegistry.register(new FakeLoadBalancerProvider(PRIORITY_POLICY_NAME)); + lbRegistry.register(new FakeLoadBalancerProvider(CDS_POLICY_NAME)); lbRegistry.register(new FakeLoadBalancerProvider(CLUSTER_RESOLVER_POLICY_NAME)); - lbRegistry.register(new PriorityLoadBalancerProvider()); - lbRegistry.register(new CdsLoadBalancerProvider()); lbRegistry.register(new FakeLoadBalancerProvider("round_robin")); lbRegistry.register( new FakeLoadBalancerProvider("ring_hash_experimental", new RingHashLoadBalancerProvider())); @@ -428,13 +429,24 @@ public void discoverAggregateCluster() { assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME); - PriorityLoadBalancerProvider.PriorityLbConfig childLbConfig = (PriorityLoadBalancerProvider.PriorityLbConfig) childBalancer.config; + PriorityLoadBalancerProvider.PriorityLbConfig childLbConfig = + (PriorityLoadBalancerProvider.PriorityLbConfig) childBalancer.config; assertThat(childLbConfig.priorities).hasSize(2); assertThat(childLbConfig.priorities.get(0)).isEqualTo(cluster1); assertThat(childLbConfig.priorities.get(1)).isEqualTo(cluster2); assertThat(childLbConfig.childConfigs).hasSize(2); - PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig1 = childLbConfig.childConfigs.get(cluster2); - System.out.println(childConfig1); + PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig1 = + childLbConfig.childConfigs.get(cluster1); + assertThat(childConfig1.toString()).isEqualTo("PriorityChildConfig{childConfig=" + + "GracefulSwitchLoadBalancer.Config{childFactory=FakeLoadBalancerProvider{policy=" + + "cds_experimental, priority=0, available=true}, childConfig=CdsConfig{name=" + + "cluster-01.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig2 = + childLbConfig.childConfigs.get(cluster2); + assertThat(childConfig2.toString()).isEqualTo("PriorityChildConfig{childConfig=" + + "GracefulSwitchLoadBalancer.Config{childFactory=FakeLoadBalancerProvider{policy=" + + "cds_experimental, priority=1, available=true}, childConfig=CdsConfig{name=" + + "cluster-02.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); } @Test diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index ad3eb01f878..5c1f3d9f44e 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -737,15 +737,15 @@ public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints2 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint2, 100, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint2, 100, true /* isHealthy */, + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); @@ -764,15 +764,15 @@ public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints2 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint2, 200, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint2, 200, true /* isHealthy */, + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority2 = CLUSTER1 + "[child2]"; xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, From 6f0a920e9fea54b2c5a47496c61dbec9a3b8e6b4 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Thu, 26 Jun 2025 18:37:32 +0530 Subject: [PATCH 08/24] Revert "Add Docker fiels for xds example server and client." This reverts commit ed5072e1481c2f355e4f8b2e3eab92f1a7a7b7cd. --- examples/example-xds/xds-client.Dockerfile | 47 ---------------------- examples/example-xds/xds-server.Dockerfile | 47 ---------------------- 2 files changed, 94 deletions(-) delete mode 100644 examples/example-xds/xds-client.Dockerfile delete mode 100644 examples/example-xds/xds-server.Dockerfile diff --git a/examples/example-xds/xds-client.Dockerfile b/examples/example-xds/xds-client.Dockerfile deleted file mode 100644 index 0f34d219177..00000000000 --- a/examples/example-xds/xds-client.Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2024 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. - -# -# Stage 1: Build XDS client -# - -FROM eclipse-temurin:11-jdk AS build - -WORKDIR /grpc-java/examples -COPY . . - -RUN cd example-xds && ../gradlew installDist -PskipCodegen=true -PskipAndroid=true - -# -# Stage 2: -# -# - Copy only the necessary files to reduce Docker image size. -# - Have an ENTRYPOINT script which will launch the XDS client -# with the given parameters. -# - -FROM eclipse-temurin:11-jre - -WORKDIR /grpc-java/ -COPY --from=build /grpc-java/examples/example-xds/build/install/example-xds/. . - -# Intentionally after the COPY to force the update on each build. -# Update Ubuntu system packages: -RUN apt-get update \ - && apt-get -y upgrade \ - && apt-get -y autoremove \ - && rm -rf /var/lib/apt/lists/* - -# Client -ENTRYPOINT ["bin/xds-hello-world-client"] diff --git a/examples/example-xds/xds-server.Dockerfile b/examples/example-xds/xds-server.Dockerfile deleted file mode 100644 index 542fb0263af..00000000000 --- a/examples/example-xds/xds-server.Dockerfile +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2024 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. - -# -# Stage 1: Build XDS server -# - -FROM eclipse-temurin:11-jdk AS build - -WORKDIR /grpc-java/examples -COPY . . - -RUN cd example-xds && ../gradlew installDist -PskipCodegen=true -PskipAndroid=true - -# -# Stage 2: -# -# - Copy only the necessary files to reduce Docker image size. -# - Have an ENTRYPOINT script which will launch the XDS server -# with the given parameters. -# - -FROM eclipse-temurin:11-jre - -WORKDIR /grpc-java/ -COPY --from=build /grpc-java/examples/example-xds/build/install/example-xds/. . - -# Intentionally after the COPY to force the update on each build. -# Update Ubuntu system packages: -RUN apt-get update \ - && apt-get -y upgrade \ - && apt-get -y autoremove \ - && rm -rf /var/lib/apt/lists/* - -# Server -ENTRYPOINT ["bin/xds-hello-world-server"] From d816b8e1c1d770c0d70fc5a43b1dab08f0934644 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Sat, 28 Jun 2025 00:33:42 +0530 Subject: [PATCH 09/24] Changes --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 34 ++- .../io/grpc/xds/CdsLoadBalancerProvider.java | 18 +- .../ClusterResolverLoadBalancerProvider.java | 4 +- .../io/grpc/xds/CdsLoadBalancer2Test.java | 78 +++++- .../xds/ClusterResolverLoadBalancerTest.java | 236 +++++++++++++----- 5 files changed, 268 insertions(+), 102 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index bbbab065db3..b898359a866 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -23,7 +23,6 @@ import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; import static java.util.Objects.requireNonNull; -import com.google.common.annotations.VisibleForTesting; import com.google.errorprone.annotations.CheckReturnValue; import io.grpc.InternalLogId; import io.grpc.LoadBalancer; @@ -64,14 +63,9 @@ final class CdsLoadBalancer2 extends LoadBalancer { private Subscription clusterSubscription; private LoadBalancer childLb; - CdsLoadBalancer2(Helper helper) { - this(helper, LoadBalancerRegistry.getDefaultRegistry()); - } - - @VisibleForTesting CdsLoadBalancer2(Helper helper, LoadBalancerRegistry lbRegistry) { this.helper = checkNotNull(helper, "helper"); - this.lbRegistry = checkNotNull(lbRegistry, "lbRegistry"); + this.lbRegistry = lbRegistry; logger = XdsLogger.withLogId(InternalLogId.allocate("cds-lb", helper.getAuthority())); logger.log(XdsLogLevel.INFO, "Created"); } @@ -122,21 +116,21 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { DiscoveryMechanism instance; if (result.clusterType() == ClusterType.EDS) { instance = DiscoveryMechanism.forEds( - clusterName, - result.edsServiceName(), - result.lrsServerInfo(), - result.maxConcurrentRequests(), - result.upstreamTlsContext(), - result.filterMetadata(), - result.outlierDetection()); + clusterName, + result.edsServiceName(), + result.lrsServerInfo(), + result.maxConcurrentRequests(), + result.upstreamTlsContext(), + result.filterMetadata(), + result.outlierDetection()); } else { instance = DiscoveryMechanism.forLogicalDns( - clusterName, - result.dnsHostName(), - result.lrsServerInfo(), - result.maxConcurrentRequests(), - result.upstreamTlsContext(), - result.filterMetadata()); + clusterName, + result.dnsHostName(), + result.lrsServerInfo(), + result.maxConcurrentRequests(), + result.upstreamTlsContext(), + result.filterMetadata()); } childConfig = new ClusterResolverConfig( instance, diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancerProvider.java index 9b242822f6c..875af9089ed 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancerProvider.java @@ -23,6 +23,7 @@ import io.grpc.LoadBalancer; 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.internal.JsonUtil; @@ -51,9 +52,24 @@ public String getPolicyName() { return XdsLbPolicies.CDS_POLICY_NAME; } + private final LoadBalancerRegistry loadBalancerRegistry; + + public CdsLoadBalancerProvider() { + this.loadBalancerRegistry = null; + } + + public CdsLoadBalancerProvider(LoadBalancerRegistry loadBalancerRegistry) { + this.loadBalancerRegistry = loadBalancerRegistry; + } + @Override public LoadBalancer newLoadBalancer(Helper helper) { - return new CdsLoadBalancer2(helper); + LoadBalancerRegistry loadBalancerRegistry = this.loadBalancerRegistry; + if (loadBalancerRegistry == null) { + loadBalancerRegistry = LoadBalancerRegistry.getDefaultRegistry(); + } + + return new CdsLoadBalancer2(helper, loadBalancerRegistry); } @Override diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java index 7b8099664b1..d871205f8eb 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java @@ -69,14 +69,14 @@ public LoadBalancer newLoadBalancer(Helper helper) { } static final class ClusterResolverConfig { - // Clusters to be resolved. + // Cluster to be resolved. final DiscoveryMechanism discoveryMechanism; // GracefulSwitch configuration final Object lbConfig; private final boolean isHttp11ProxyAvailable; ClusterResolverConfig(DiscoveryMechanism discoveryMechanism, Object lbConfig, - boolean isHttp11ProxyAvailable) { + boolean isHttp11ProxyAvailable) { this.discoveryMechanism = checkNotNull(discoveryMechanism, "discoveryMechanism"); this.lbConfig = checkNotNull(lbConfig, "lbConfig"); this.isHttp11ProxyAvailable = isHttp11ProxyAvailable; diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index eeaba404679..23a2ad275e2 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -17,7 +17,6 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; -import static io.grpc.xds.XdsLbPolicies.CDS_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; import static io.grpc.xds.XdsTestControlPlaneService.ADS_TYPE_URL_CDS; @@ -152,8 +151,6 @@ public class CdsLoadBalancer2Test { @Before public void setUp() throws Exception { - lbRegistry.register(new FakeLoadBalancerProvider(PRIORITY_POLICY_NAME)); - lbRegistry.register(new FakeLoadBalancerProvider(CDS_POLICY_NAME)); lbRegistry.register(new FakeLoadBalancerProvider(CLUSTER_RESOLVER_POLICY_NAME)); lbRegistry.register(new FakeLoadBalancerProvider("round_robin")); lbRegistry.register( @@ -162,7 +159,9 @@ public void setUp() throws Exception { new LeastRequestLoadBalancerProvider())); lbRegistry.register(new FakeLoadBalancerProvider("wrr_locality_experimental", new WrrLocalityLoadBalancerProvider())); - loadBalancer = new CdsLoadBalancer2(helper, lbRegistry); + CdsLoadBalancerProvider cdsLoadBalancerProvider = new CdsLoadBalancerProvider(lbRegistry); + lbRegistry.register(cdsLoadBalancerProvider); + loadBalancer = (CdsLoadBalancer2) cdsLoadBalancerProvider.newLoadBalancer(helper); cleanupRule.register(InProcessServerBuilder .forName("control-plane.example.com") @@ -407,11 +406,16 @@ public void dynamicCluster() { } @Test - public void discoverAggregateCluster() { + public void discoverAggregateCluster_createsPriorityLbPolicy() { + lbRegistry.register(new FakeLoadBalancerProvider(PRIORITY_POLICY_NAME)); + CdsLoadBalancerProvider cdsLoadBalancerProvider = new CdsLoadBalancerProvider(lbRegistry); + lbRegistry.register(cdsLoadBalancerProvider); + loadBalancer = (CdsLoadBalancer2) cdsLoadBalancerProvider.newLoadBalancer(helper); + String cluster1 = "cluster-01.googleapis.com"; String cluster2 = "cluster-02.googleapis.com"; controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of( - // cluster1 (aggr.) -> [cluster2 (EDS), cluster3 (EDS)] + // CLUSTER (aggr.) -> [cluster1 (EDS), cluster2 (EDS)] CLUSTER, Cluster.newBuilder() .setName(CLUSTER) .setClusterType(Cluster.CustomClusterType.newBuilder() @@ -438,15 +442,60 @@ public void discoverAggregateCluster() { PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig1 = childLbConfig.childConfigs.get(cluster1); assertThat(childConfig1.toString()).isEqualTo("PriorityChildConfig{childConfig=" - + "GracefulSwitchLoadBalancer.Config{childFactory=FakeLoadBalancerProvider{policy=" - + "cds_experimental, priority=0, available=true}, childConfig=CdsConfig{name=" - + "cluster-01.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" + + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" + + "name=cluster-01.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig2 = childLbConfig.childConfigs.get(cluster2); assertThat(childConfig2.toString()).isEqualTo("PriorityChildConfig{childConfig=" - + "GracefulSwitchLoadBalancer.Config{childFactory=FakeLoadBalancerProvider{policy=" - + "cds_experimental, priority=1, available=true}, childConfig=CdsConfig{name=" - + "cluster-02.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" + + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" + + "name=cluster-02.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + } + + @Test + // Both priorities will get tried using real priority LB policy. + public void discoverAggregateCluster_testChildCdsLbPolicyParsing() { + lbRegistry.register(new PriorityLoadBalancerProvider()); + CdsLoadBalancerProvider cdsLoadBalancerProvider = new CdsLoadBalancerProvider(lbRegistry); + lbRegistry.register(cdsLoadBalancerProvider); + loadBalancer = (CdsLoadBalancer2) cdsLoadBalancerProvider.newLoadBalancer(helper); + + String cluster1 = "cluster-01.googleapis.com"; + String cluster2 = "cluster-02.googleapis.com"; + controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of( + // CLUSTER (aggr.) -> [cluster1 (EDS), cluster2 (EDS)] + CLUSTER, Cluster.newBuilder() + .setName(CLUSTER) + .setClusterType(Cluster.CustomClusterType.newBuilder() + .setName("envoy.clusters.aggregate") + .setTypedConfig(Any.pack(ClusterConfig.newBuilder() + .addClusters(cluster1) + .addClusters(cluster2) + .build()))) + .build(), + cluster1, EDS_CLUSTER.toBuilder().setName(cluster1).build(), + cluster2, EDS_CLUSTER.toBuilder().setName(cluster2).build())); + startXdsDepManager(); + + verify(helper, never()).updateBalancingState(eq(ConnectivityState.TRANSIENT_FAILURE), any()); + assertThat(childBalancers).hasSize(2); + ClusterResolverConfig cluster1ResolverConfig = + (ClusterResolverConfig) childBalancers.get(0).config; + assertThat(cluster1ResolverConfig.discoveryMechanism.cluster) + .isEqualTo("cluster-01.googleapis.com"); + assertThat(cluster1ResolverConfig.discoveryMechanism.type) + .isEqualTo(DiscoveryMechanism.Type.EDS); + assertThat(cluster1ResolverConfig.discoveryMechanism.edsServiceName) + .isEqualTo("backend-service-1.googleapis.com"); + ClusterResolverConfig cluster2ResolverConfig = + (ClusterResolverConfig) childBalancers.get(1).config; + assertThat(cluster2ResolverConfig.discoveryMechanism.cluster) + .isEqualTo("cluster-02.googleapis.com"); + assertThat(cluster2ResolverConfig.discoveryMechanism.type) + .isEqualTo(DiscoveryMechanism.Type.EDS); + assertThat(cluster2ResolverConfig.discoveryMechanism.edsServiceName) + .isEqualTo("backend-service-1.googleapis.com"); } @Test @@ -474,6 +523,11 @@ public void aggregateCluster_noChildren() { @Test public void aggregateCluster_noNonAggregateClusterExits_returnErrorPicker() { + lbRegistry.register(new PriorityLoadBalancerProvider()); + CdsLoadBalancerProvider cdsLoadBalancerProvider = new CdsLoadBalancerProvider(lbRegistry); + lbRegistry.register(cdsLoadBalancerProvider); + loadBalancer = (CdsLoadBalancer2) cdsLoadBalancerProvider.newLoadBalancer(helper); + String cluster1 = "cluster-01.googleapis.com"; controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of( // CLUSTER (aggr.) -> [cluster1 (missing)] diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index 5c1f3d9f44e..e82a805b0e7 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -384,27 +384,27 @@ public void edsClustersEndpointHostname_addedToAddressAttribute() { @Test public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); + edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); EquivalentAddressGroup endpoint = - new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); + new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.1", 8080)); // Proxy address in endpointMetadata (use FakeSocketAddress directly) SocketAddress proxyAddress = new FakeSocketAddress("127.0.0.2"); ImmutableMap endpointMetadata = - ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); + ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); // No proxy in locality metadata ImmutableMap localityMetadata = ImmutableMap.of(); LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, - "hostname1", endpointMetadata)), - 100 /* localityWeight */, 1 /* priority */, localityMetadata); + Arrays.asList( + LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, + "hostname1", endpointMetadata)), + 100 /* localityWeight */, 1 /* priority */, localityMetadata); xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, @@ -448,10 +448,10 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, - "hostname2", endpointMetadata)), - 100 /* localityWeight */, 1 /* priority */, localityMetadata); + Arrays.asList( + LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true, + "hostname2", endpointMetadata)), + 100 /* localityWeight */, 1 /* priority */, localityMetadata); xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, @@ -646,19 +646,6 @@ private LocalityLbEndpoints createEndpoints(int priority) { 70 /* localityWeight */, priority /* priority */, ImmutableMap.of()); } - private void deliverLbConfig(ClusterResolverConfig config) { - loadBalancer.acceptResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes( - // Other attributes not used by cluster_resolver LB are omitted. - Attributes.newBuilder() - .set(XdsAttributes.XDS_CLIENT_POOL, xdsClientPool) - .build()) - .setLoadBalancingPolicyConfig(config) - .build()); - } - @Test public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { ClusterResolverConfig config = new ClusterResolverConfig( @@ -701,27 +688,27 @@ public void edsCluster_resourcesRevoked_shutDownChildLbPolicy() { xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); Status expectedError = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)); + "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)); assertPicker(pickerCaptor.getValue(), expectedError, null); } @Test public void handleEdsResource_ignoreUnhealthyEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of()), - LbEndpoint.create(endpoint2, 100, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Arrays.asList( + LbEndpoint.create(endpoint1, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of()), + LbEndpoint.create(endpoint2, 100, true /* isHealthy */, + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); @@ -732,7 +719,7 @@ public void handleEdsResource_ignoreUnhealthyEndpoints() { @Test public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); @@ -759,7 +746,7 @@ public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { @Test public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); @@ -775,8 +762,8 @@ public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority2 = CLUSTER1 + "[child2]"; xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(((PriorityLbConfig) childBalancer.config).priorities).containsExactly(priority2); @@ -785,25 +772,25 @@ public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { @Test public void handleEdsResource_noHealthyEndpoint() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); EquivalentAddressGroup endpoint = makeAddress("endpoint-addr-1"); LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint, 100, false /* isHealthy */, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment(EDS_SERVICE_NAME1, - Collections.singletonMap(locality1, localityLbEndpoints)); // single endpoint, unhealthy + Collections.singletonMap(locality1, localityLbEndpoints)); // single endpoint, unhealthy assertThat(childBalancers).isEmpty(); verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); assertPicker( - pickerCaptor.getValue(), - Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Collections.singleton(CLUSTER1)), - null); + pickerCaptor.getValue(), + Status.UNAVAILABLE.withDescription( + "No usable endpoint from cluster(s): " + Collections.singleton(CLUSTER1)), + null); } @Test @@ -820,7 +807,7 @@ public void oldListenerCallback_onlyLogicalDnsCluster_endpointsResolved() { void do_onlyLogicalDnsCluster_endpointsResolved() { ClusterResolverConfig config = new ClusterResolverConfig( - logicalDnsDiscoveryMechanism, roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -836,23 +823,23 @@ void do_onlyLogicalDnsCluster_endpointsResolved() { PriorityChildConfig priorityChildConfig = priorityLbConfig.childConfigs.get(priority); assertThat(priorityChildConfig.ignoreReresolution).isFalse(); assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); + .getPolicyName()) + .isEqualTo(CLUSTER_IMPL_POLICY_NAME); ClusterImplConfig clusterImplConfig = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig.childConfig); assertClusterImplConfig(clusterImplConfig, CLUSTER_DNS, null, LRS_SERVER_INFO, 300L, null, - Collections.emptyList(), "pick_first"); + Collections.emptyList(), "pick_first"); assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses); assertThat(childBalancer.addresses.get(0).getAttributes() - .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); + .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); assertThat(childBalancer.addresses.get(1).getAttributes() - .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); + .get(XdsAttributes.ATTR_ADDRESS_NAME)).isEqualTo(DNS_HOST_NAME); } @Test public void onlyLogicalDnsCluster_handleRefreshNameResolution() { ClusterResolverConfig config = new ClusterResolverConfig( - logicalDnsDiscoveryMechanism, roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -879,9 +866,9 @@ public void oldListenerCallback_resolutionError_backoffAndRefresh() { void do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { InOrder inOrder = Mockito.inOrder(helper, backoffPolicyProvider, - backoffPolicy1, backoffPolicy2); + backoffPolicy1, backoffPolicy2); ClusterResolverConfig config = new ClusterResolverConfig( - logicalDnsDiscoveryMechanism, roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -927,7 +914,7 @@ void do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() { public void onlyLogicalDnsCluster_refreshNameResolutionRaceWithResolutionError() { InOrder inOrder = Mockito.inOrder(backoffPolicyProvider, backoffPolicy1, backoffPolicy2); ClusterResolverConfig config = new ClusterResolverConfig( - logicalDnsDiscoveryMechanism, roundRobin, false); + logicalDnsDiscoveryMechanism, roundRobin, false); deliverLbConfig(config); FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); assertThat(childBalancers).isEmpty(); @@ -965,17 +952,17 @@ public void onlyLogicalDnsCluster_refreshNameResolutionRaceWithResolutionError() @Test public void resolutionErrorAfterChildLbCreated_propagateError() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); reset(helper); EquivalentAddressGroup endpoint = makeAddress("endpoint-addr-1"); LocalityLbEndpoints localityLbEndpoints = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint, 100, true, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint, 100, true, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); @@ -987,10 +974,125 @@ public void resolutionErrorAfterChildLbCreated_propagateError() { xdsClient.deliverError(Status.RESOURCE_EXHAUSTED.withDescription("out of memory")); assertThat(childBalancer.upstreamError).isNotNull(); // last cluster's (DNS) error propagated assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE); - assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("Unable to load EDS backend-service-foo.googleapis.com. xDS server returned: RESOURCE_EXHAUSTED: out of memory"); + assertThat(childBalancer.upstreamError.getDescription()) + .isEqualTo("Unable to load EDS backend-service-foo.googleapis.com. xDS server returned: " + + "RESOURCE_EXHAUSTED: out of memory"); assertThat(childBalancer.shutdown).isFalse(); verify(helper, never()).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), any(SubchannelPicker.class)); + eq(ConnectivityState.TRANSIENT_FAILURE), any(SubchannelPicker.class)); + } + + @Test + public void resolutionErrorBeforeChildLbCreated_returnErrorPicker() { + ClusterResolverConfig config = new ClusterResolverConfig( + edsDiscoveryMechanism1, roundRobin, false); + deliverLbConfig(config); + assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); + assertThat(childBalancers).isEmpty(); + reset(helper); + xdsClient.deliverError(Status.RESOURCE_EXHAUSTED.withDescription("OOM")); + assertThat(childBalancers).isEmpty(); + verify(helper).updateBalancingState( + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + PickResult result = pickerCaptor.getValue().pickSubchannel(mock(PickSubchannelArgs.class)); + Status actualStatus = result.getStatus(); + assertThat(actualStatus.getCode()).isEqualTo(Status.Code.UNAVAILABLE); + assertThat(actualStatus.getDescription()).contains("RESOURCE_EXHAUSTED: OOM"); + } + + @Test + public void handleNameResolutionErrorFromUpstream_eds_beforeChildLbCreated_returnErrorPicker() { + ClusterResolverConfig config = new ClusterResolverConfig( + edsDiscoveryMechanism1, roundRobin, false); + deliverLbConfig(config); + assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); + assertThat(childBalancers).isEmpty(); + reset(helper); + Status upstreamError = Status.UNAVAILABLE.withDescription("unreachable"); + loadBalancer.handleNameResolutionError(upstreamError); + verify(helper).updateBalancingState( + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + assertPicker(pickerCaptor.getValue(), upstreamError, null); + } + + @Test + public void handleNameResolutionErrorFromUpstream_lDns_beforeChildLbCreated_returnErrorPicker() { + ClusterResolverConfig config = new ClusterResolverConfig( + logicalDnsDiscoveryMechanism, roundRobin, false); + deliverLbConfig(config); + assertResolverCreated("/" + DNS_HOST_NAME); + assertThat(childBalancers).isEmpty(); + reset(helper); + Status upstreamError = Status.UNAVAILABLE.withDescription("unreachable"); + loadBalancer.handleNameResolutionError(upstreamError); + verify(helper).updateBalancingState( + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + assertPicker(pickerCaptor.getValue(), upstreamError, null); + } + + @Test + public void handleNameResolutionErrorFromUpstream_afterChildLbCreated_eds_fallThrough() { + ClusterResolverConfig config = new ClusterResolverConfig( + edsDiscoveryMechanism1, roundRobin, false); + deliverLbConfig(config); + assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); + assertThat(childBalancers).isEmpty(); + reset(helper); + EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); + LocalityLbEndpoints localityLbEndpoints = + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, true, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + xdsClient.deliverClusterLoadAssignment( + EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); + assertThat(childBalancers).hasSize(1); + FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); + assertThat(((PriorityLbConfig) childBalancer.config).priorities) + .containsExactly(CLUSTER1 + "[child1]"); + assertAddressesEqual(Arrays.asList(endpoint1), childBalancer.addresses); + + loadBalancer.handleNameResolutionError(Status.UNAVAILABLE.withDescription("unreachable")); + assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE); + assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("unreachable"); + verify(helper, never()).updateBalancingState( + any(ConnectivityState.class), any(SubchannelPicker.class)); + } + + @Test + public void handleNameResolutionErrorFromUpstream_afterChildLbCreated_logicalDns_fallThrough() { + ClusterResolverConfig config = new ClusterResolverConfig( + logicalDnsDiscoveryMechanism, roundRobin, false); + deliverLbConfig(config); + FakeNameResolver resolver = assertResolverCreated("/" + DNS_HOST_NAME); + assertThat(childBalancers).isEmpty(); + reset(helper); + EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2"); + resolver.deliverEndpointAddresses(Collections.singletonList(endpoint2)); + assertThat(childBalancers).hasSize(1); + FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); + assertThat(((PriorityLbConfig) childBalancer.config).priorities) + .containsExactly(CLUSTER_DNS + "[child0]"); + assertAddressesEqual(Arrays.asList(endpoint2), childBalancer.addresses); + + loadBalancer.handleNameResolutionError(Status.UNAVAILABLE.withDescription("unreachable")); + assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE); + assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("unreachable"); + verify(helper, never()).updateBalancingState( + any(ConnectivityState.class), any(SubchannelPicker.class)); + } + + private void deliverLbConfig(ClusterResolverConfig config) { + loadBalancer.acceptResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(Collections.emptyList()) + .setAttributes( + // Other attributes not used by cluster_resolver LB are omitted. + Attributes.newBuilder() + .set(XdsAttributes.XDS_CLIENT_POOL, xdsClientPool) + .build()) + .setLoadBalancingPolicyConfig(config) + .build()); } private FakeNameResolver assertResolverCreated(String uriPath) { From c8eca59564169504b84e092d758386491e490971 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Sat, 28 Jun 2025 00:45:56 +0530 Subject: [PATCH 10/24] whitespace changes nightmares --- .../xds/ClusterResolverLoadBalancerTest.java | 118 +++++++++--------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index e82a805b0e7..a8ce6e23653 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -407,22 +407,22 @@ public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { 100 /* localityWeight */, 1 /* priority */, localityMetadata); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints)); assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); // Get the rewritten address SocketAddress rewrittenAddress = - childBalancer.addresses.get(0).getAddresses().get(0); + childBalancer.addresses.get(0).getAddresses().get(0); assertThat(rewrittenAddress).isInstanceOf(HttpConnectProxiedSocketAddress.class); HttpConnectProxiedSocketAddress proxiedSocket = - (HttpConnectProxiedSocketAddress) rewrittenAddress; + (HttpConnectProxiedSocketAddress) rewrittenAddress; // Assert that the target address is the original address assertThat(proxiedSocket.getTargetAddress()) - .isEqualTo(endpoint.getAddresses().get(0)); + .isEqualTo(endpoint.getAddresses().get(0)); // Assert that the proxy address is correctly set assertThat(proxiedSocket.getProxyAddress()).isEqualTo(proxyAddress); @@ -431,13 +431,13 @@ public void endpointAddressRewritten_whenProxyMetadataIsInEndpointMetadata() { @Test public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); + edsDiscoveryMechanismWithOutlierDetection, leastRequest, true); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); EquivalentAddressGroup endpoint = - new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.2", 8080)); + new EquivalentAddressGroup(InetSocketAddress.createUnresolved("127.0.0.2", 8080)); // No proxy in endpointMetadata ImmutableMap endpointMetadata = ImmutableMap.of(); @@ -445,7 +445,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { // Proxy address is now in localityMetadata SocketAddress proxyAddress = new FakeSocketAddress("proxy-addr"); ImmutableMap localityMetadata = - ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); + ImmutableMap.of("envoy.http11_proxy_transport_socket.proxy_address", proxyAddress); LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create( Arrays.asList( @@ -454,8 +454,8 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { 100 /* localityWeight */, 1 /* priority */, localityMetadata); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints)); assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); @@ -466,7 +466,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { // Assert that the address was rewritten assertThat(rewrittenAddress).isInstanceOf(HttpConnectProxiedSocketAddress.class); HttpConnectProxiedSocketAddress proxiedSocket = - (HttpConnectProxiedSocketAddress) rewrittenAddress; + (HttpConnectProxiedSocketAddress) rewrittenAddress; // Assert that the target address is the original address assertThat(proxiedSocket.getTargetAddress()).isEqualTo(endpoint.getAddresses().get(0)); @@ -478,7 +478,7 @@ public void endpointAddressRewritten_whenProxyMetadataIsInLocalityMetadata() { @Test public void onlyEdsClusters_receivedEndpoints() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism2, roundRobin, false); + edsDiscoveryMechanism2, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME2); assertThat(childBalancers).isEmpty(); @@ -497,10 +497,10 @@ public void onlyEdsClusters_receivedEndpoints() { true, "hostname1", ImmutableMap.of())), 70 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints3 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint4, 100, true, - "hostname3", ImmutableMap.of())), - 20 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint4, 100, true, + "hostname3", ImmutableMap.of())), + 20 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority1 = CLUSTER2 + "[child1]"; String priority2 = CLUSTER2 + "[child2]"; @@ -515,56 +515,56 @@ public void onlyEdsClusters_receivedEndpoints() { assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME); PriorityLbConfig priorityLbConfig = (PriorityLbConfig) childBalancer.config; assertThat(priorityLbConfig.priorities) - .containsExactly(priority1, priority2).inOrder(); + .containsExactly(priority1, priority2).inOrder(); PriorityChildConfig priorityChildConfig1 = priorityLbConfig.childConfigs.get(priority1); assertThat(priorityChildConfig1.ignoreReresolution).isTrue(); assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig1.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); + .getPolicyName()) + .isEqualTo(CLUSTER_IMPL_POLICY_NAME); ClusterImplConfig clusterImplConfig1 = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig1.childConfig); assertClusterImplConfig(clusterImplConfig1, CLUSTER2, EDS_SERVICE_NAME2, LRS_SERVER_INFO, 200L, - tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); + tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); WrrLocalityConfig wrrLocalityConfig1 = (WrrLocalityConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); LoadBalancerProvider childProvider1 = - GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig1.childConfig); assertThat(childProvider1.getPolicyName()).isEqualTo("round_robin"); PriorityChildConfig priorityChildConfig2 = priorityLbConfig.childConfigs.get(priority2); assertThat(priorityChildConfig2.ignoreReresolution).isTrue(); assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig2.childConfig) - .getPolicyName()) - .isEqualTo(CLUSTER_IMPL_POLICY_NAME); + .getPolicyName()) + .isEqualTo(CLUSTER_IMPL_POLICY_NAME); ClusterImplConfig clusterImplConfig2 = (ClusterImplConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig2.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig2.childConfig); assertClusterImplConfig(clusterImplConfig2, CLUSTER2, EDS_SERVICE_NAME2, LRS_SERVER_INFO, 200L, - tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); + tlsContext, Collections.emptyList(), WRR_LOCALITY_POLICY_NAME); WrrLocalityConfig wrrLocalityConfig2 = (WrrLocalityConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); LoadBalancerProvider childProvider2 = - GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig2.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig2.childConfig); assertThat(childProvider2.getPolicyName()).isEqualTo("round_robin"); WrrLocalityConfig wrrLocalityConfig3 = (WrrLocalityConfig) - GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig); LoadBalancerProvider childProvider3 = - GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig3.childConfig); + GracefulSwitchLoadBalancerAccessor.getChildProvider(wrrLocalityConfig3.childConfig); assertThat(childProvider3.getPolicyName()).isEqualTo("round_robin"); for (EquivalentAddressGroup eag : childBalancer.addresses) { if (eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY) == locality1) { assertThat(eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY_WEIGHT)) - .isEqualTo(70); + .isEqualTo(70); } if (eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY) == locality2) { assertThat(eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY_WEIGHT)) - .isEqualTo(10); + .isEqualTo(10); } if (eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY) == locality3) { assertThat(eag.getAttributes().get(XdsAttributes.ATTR_LOCALITY_WEIGHT)) - .isEqualTo(20); + .isEqualTo(20); } } } @@ -573,15 +573,15 @@ public void onlyEdsClusters_receivedEndpoints() { private void verifyEdsPriorityNames(List want, Map... updates) { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism2, roundRobin, false); + edsDiscoveryMechanism2, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME2); assertThat(childBalancers).isEmpty(); for (Map update: updates) { xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME2, - update); + EDS_SERVICE_NAME2, + update); } assertThat(childBalancers).hasSize(1); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); @@ -612,14 +612,14 @@ public void edsUpdatePriorityName_addOnePriority() { @SuppressWarnings("unchecked") public void edsUpdatePriorityName_swapTwoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child2]", CLUSTER2 + "[child1]", - CLUSTER2 + "[child3]"), - ImmutableMap.of(locality1, createEndpoints(1), - locality2, createEndpoints(2), - locality3, createEndpoints(3) - ), - ImmutableMap.of(locality1, createEndpoints(2), - locality2, createEndpoints(1), - locality3, createEndpoints(3)) + CLUSTER2 + "[child3]"), + ImmutableMap.of(locality1, createEndpoints(1), + locality2, createEndpoints(2), + locality3, createEndpoints(3) + ), + ImmutableMap.of(locality1, createEndpoints(2), + locality2, createEndpoints(1), + locality3, createEndpoints(3)) ); } @@ -627,29 +627,29 @@ locality3, createEndpoints(3)) @SuppressWarnings("unchecked") public void edsUpdatePriorityName_mergeTwoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child3]", CLUSTER2 + "[child1]"), - ImmutableMap.of(locality1, createEndpoints(1), - locality3, createEndpoints(3), - locality2, createEndpoints(2)), - ImmutableMap.of(locality1, createEndpoints(2), - locality3, createEndpoints(1), - locality2, createEndpoints(1) - )); + ImmutableMap.of(locality1, createEndpoints(1), + locality3, createEndpoints(3), + locality2, createEndpoints(2)), + ImmutableMap.of(locality1, createEndpoints(2), + locality3, createEndpoints(1), + locality2, createEndpoints(1) + )); } private LocalityLbEndpoints createEndpoints(int priority) { return LocalityLbEndpoints.create( - Arrays.asList( - LbEndpoint.create(makeAddress("endpoint-addr-1"), 100, - true, "hostname1", ImmutableMap.of()), - LbEndpoint.create(makeAddress("endpoint-addr-2"), 100, - true, "hostname2", ImmutableMap.of())), - 70 /* localityWeight */, priority /* priority */, ImmutableMap.of()); + Arrays.asList( + LbEndpoint.create(makeAddress("endpoint-addr-1"), 100, + true, "hostname1", ImmutableMap.of()), + LbEndpoint.create(makeAddress("endpoint-addr-2"), 100, + true, "hostname2", ImmutableMap.of())), + 70 /* localityWeight */, priority /* priority */, ImmutableMap.of()); } @Test public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); From 4b9206692b1cac9cfa29e0aa88063aae5f16e760 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Sat, 28 Jun 2025 00:50:31 +0530 Subject: [PATCH 11/24] whitespace changes nightmares --- .../xds/ClusterResolverLoadBalancerTest.java | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index a8ce6e23653..4adea120450 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -594,18 +594,18 @@ private void verifyEdsPriorityNames(List want, @SuppressWarnings("unchecked") public void edsUpdatePriorityName_twoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child1]", CLUSTER2 + "[child2]"), - ImmutableMap.of(locality1, createEndpoints(1), - locality2, createEndpoints(2) - )); + ImmutableMap.of(locality1, createEndpoints(1), + locality2, createEndpoints(2) + )); } @Test @SuppressWarnings("unchecked") public void edsUpdatePriorityName_addOnePriority() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child2]"), - ImmutableMap.of(locality1, createEndpoints(1)), - ImmutableMap.of(locality2, createEndpoints(1) - )); + ImmutableMap.of(locality1, createEndpoints(1)), + ImmutableMap.of(locality2, createEndpoints(1) + )); } @Test @@ -628,11 +628,11 @@ locality3, createEndpoints(3)) public void edsUpdatePriorityName_mergeTwoPriorities() { verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child3]", CLUSTER2 + "[child1]"), ImmutableMap.of(locality1, createEndpoints(1), - locality3, createEndpoints(3), - locality2, createEndpoints(2)), + locality3, createEndpoints(3), + locality2, createEndpoints(2)), ImmutableMap.of(locality1, createEndpoints(2), - locality3, createEndpoints(1), - locality2, createEndpoints(1) + locality3, createEndpoints(1), + locality2, createEndpoints(1) )); } @@ -657,30 +657,30 @@ public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { xdsClient.deliverResourceNotFound(EDS_SERVICE_NAME1); verify(helper).updateBalancingState( - eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); + eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); assertPicker( - pickerCaptor.getValue(), - Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)), - null); + pickerCaptor.getValue(), + Status.UNAVAILABLE.withDescription( + "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)), + null); } @Test public void edsCluster_resourcesRevoked_shutDownChildLbPolicy() { ClusterResolverConfig config = new ClusterResolverConfig( - edsDiscoveryMechanism1, roundRobin, false); + edsDiscoveryMechanism1, roundRobin, false); deliverLbConfig(config); assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1); assertThat(childBalancers).isEmpty(); reset(helper); EquivalentAddressGroup endpoint1 = makeAddress("endpoint-addr-1"); LocalityLbEndpoints localityLbEndpoints1 = - LocalityLbEndpoints.create( - Collections.singletonList(LbEndpoint.create(endpoint1, 100, true, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + LocalityLbEndpoints.create( + Collections.singletonList(LbEndpoint.create(endpoint1, 100, true, + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints1)); + EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints1)); assertThat(childBalancers).hasSize(1); // child LB policy created FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(((PriorityLbConfig) childBalancer.config).priorities).hasSize(1); @@ -710,7 +710,7 @@ public void handleEdsResource_ignoreUnhealthyEndpoints() { "hostname2", ImmutableMap.of())), 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); + EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); assertThat(childBalancer.addresses).hasSize(1); assertAddressesEqual(Collections.singletonList(endpoint2), childBalancer.addresses); @@ -734,8 +734,8 @@ public void handleEdsResource_ignoreLocalitiesWithNoHealthyEndpoints() { "hostname2", ImmutableMap.of())), 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); xdsClient.deliverClusterLoadAssignment( - EDS_SERVICE_NAME1, - ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); + EDS_SERVICE_NAME1, + ImmutableMap.of(locality1, localityLbEndpoints1, locality2, localityLbEndpoints2)); FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers); for (EquivalentAddressGroup eag : childBalancer.addresses) { @@ -753,13 +753,13 @@ public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { LocalityLbEndpoints localityLbEndpoints1 = LocalityLbEndpoints.create( Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), - 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); + "hostname1", ImmutableMap.of())), + 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints2 = LocalityLbEndpoints.create( Collections.singletonList(LbEndpoint.create(endpoint2, 200, true /* isHealthy */, - "hostname2", ImmutableMap.of())), - 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); + "hostname2", ImmutableMap.of())), + 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority2 = CLUSTER1 + "[child2]"; xdsClient.deliverClusterLoadAssignment( EDS_SERVICE_NAME1, From 3867cc72a5c204323a77a505cd34893e780dc7aa Mon Sep 17 00:00:00 2001 From: deadEternally Date: Sat, 28 Jun 2025 01:04:34 +0530 Subject: [PATCH 12/24] whitespace changes nightmares --- .../java/io/grpc/xds/ClusterResolverLoadBalancerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index 4adea120450..758a25aa066 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -753,12 +753,12 @@ public void handleEdsResource_ignorePrioritiesWithNoHealthyEndpoints() { LocalityLbEndpoints localityLbEndpoints1 = LocalityLbEndpoints.create( Collections.singletonList(LbEndpoint.create(endpoint1, 100, false /* isHealthy */, - "hostname1", ImmutableMap.of())), + "hostname1", ImmutableMap.of())), 10 /* localityWeight */, 1 /* priority */, ImmutableMap.of()); LocalityLbEndpoints localityLbEndpoints2 = LocalityLbEndpoints.create( Collections.singletonList(LbEndpoint.create(endpoint2, 200, true /* isHealthy */, - "hostname2", ImmutableMap.of())), + "hostname2", ImmutableMap.of())), 10 /* localityWeight */, 2 /* priority */, ImmutableMap.of()); String priority2 = CLUSTER1 + "[child2]"; xdsClient.deliverClusterLoadAssignment( From c4bfaa5a8d974b099bfbf818df04efcc2a87f6b0 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Mon, 30 Jun 2025 17:12:31 +0530 Subject: [PATCH 13/24] Replace clusters array with single cluster in ClusterResolverLB --- .../grpc/xds/ClusterResolverLoadBalancer.java | 47 +++++++------------ .../xds/ClusterResolverLoadBalancerTest.java | 6 +-- 2 files changed, 21 insertions(+), 32 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java index 7ce75f93f73..988adbe421b 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java @@ -168,8 +168,8 @@ public LoadBalancer newLoadBalancer(Helper helper) { */ private final class ClusterResolverLbState extends LoadBalancer { private final Helper helper; - private final List clusters = new ArrayList<>(); private final Map clusterStates = new HashMap<>(); + private String cluster; private Object endpointLbConfig; private ResolvedAddresses resolvedAddresses; private LoadBalancer childLb; @@ -186,7 +186,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { (ClusterResolverConfig) resolvedAddresses.getLoadBalancingPolicyConfig(); endpointLbConfig = config.lbConfig; DiscoveryMechanism instance = config.discoveryMechanism; - clusters.add(instance.cluster); + cluster = instance.cluster; ClusterState state; if (instance.type == DiscoveryMechanism.Type.EDS) { state = new EdsClusterState(instance.cluster, instance.edsServiceName, @@ -228,24 +228,22 @@ private void handleEndpointResourceUpdate() { List priorities = new ArrayList<>(); // totally ordered priority list Status endpointNotFound = Status.OK; - for (String cluster : clusters) { - ClusterState state = clusterStates.get(cluster); - // Propagate endpoints to the child LB policy only after all clusters have been resolved. - if (!state.resolved && state.status.isOk()) { - return; - } - if (state.result != null) { - addresses.addAll(state.result.addresses); - priorityChildConfigs.putAll(state.result.priorityChildConfigs); - priorities.addAll(state.result.priorities); - } else { - endpointNotFound = state.status; - } + ClusterState state = clusterStates.get(cluster); + // Propagate endpoints to the child LB policy only after all clusters have been resolved. + if (!state.resolved && state.status.isOk()) { + return; + } + if (state.result != null) { + addresses.addAll(state.result.addresses); + priorityChildConfigs.putAll(state.result.priorityChildConfigs); + priorities.addAll(state.result.priorities); + } else { + endpointNotFound = state.status; } if (addresses.isEmpty()) { if (endpointNotFound.isOk()) { endpointNotFound = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + clusters); + "No usable endpoint from cluster(s): " + cluster); } else { endpointNotFound = Status.UNAVAILABLE.withCause(endpointNotFound.getCause()) @@ -273,22 +271,13 @@ private void handleEndpointResourceUpdate() { } private void handleEndpointResolutionError() { - boolean allInError = true; - Status error = null; - for (String cluster : clusters) { - ClusterState state = clusterStates.get(cluster); - if (state.status.isOk()) { - allInError = false; - } else { - error = state.status; - } - } - if (allInError) { + ClusterState state = clusterStates.get(cluster); + if (!state.status.isOk()) { if (childLb != null) { - childLb.handleNameResolutionError(error); + childLb.handleNameResolutionError(state.status); } else { helper.updateBalancingState( - TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(error))); + TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(state.status))); } } } diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index 758a25aa066..b6b28d90134 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -661,7 +661,7 @@ public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { assertPicker( pickerCaptor.getValue(), Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)), + "No usable endpoint from cluster(s): " + CLUSTER1), null); } @@ -690,7 +690,7 @@ public void edsCluster_resourcesRevoked_shutDownChildLbPolicy() { verify(helper).updateBalancingState( eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); Status expectedError = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1)); + "No usable endpoint from cluster(s): " + CLUSTER1); assertPicker(pickerCaptor.getValue(), expectedError, null); } @@ -789,7 +789,7 @@ public void handleEdsResource_noHealthyEndpoint() { assertPicker( pickerCaptor.getValue(), Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + Collections.singleton(CLUSTER1)), + "No usable endpoint from cluster(s): " + CLUSTER1), null); } From 400b77642daee19ae80d79cb4c2c60eb5436bdd6 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Wed, 9 Jul 2025 13:30:29 +0530 Subject: [PATCH 14/24] Review comments, excepting the child cluster type change handling. --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 16 ++-- .../io/grpc/xds/CdsLoadBalancer2Test.java | 77 ++++++++++++++----- 2 files changed, 64 insertions(+), 29 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index b898359a866..54b5a8e6088 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -21,12 +21,10 @@ import static io.grpc.xds.XdsLbPolicies.CDS_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; import static io.grpc.xds.XdsLbPolicies.PRIORITY_POLICY_NAME; -import static java.util.Objects.requireNonNull; import com.google.errorprone.annotations.CheckReturnValue; import io.grpc.InternalLogId; import io.grpc.LoadBalancer; -import io.grpc.LoadBalancerProvider; import io.grpc.LoadBalancerRegistry; import io.grpc.NameResolver; import io.grpc.Status; @@ -47,6 +45,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -65,7 +64,7 @@ final class CdsLoadBalancer2 extends LoadBalancer { CdsLoadBalancer2(Helper helper, LoadBalancerRegistry lbRegistry) { this.helper = checkNotNull(helper, "helper"); - this.lbRegistry = lbRegistry; + this.lbRegistry = checkNotNull(lbRegistry, "lbRegistry"); logger = XdsLogger.withLogId(InternalLogId.allocate("cds-lb", helper.getAuthority())); logger.log(XdsLogLevel.INFO, "Created"); } @@ -140,13 +139,12 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { childLb = lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME).newLoadBalancer(helper); } } else if (clusterConfig.getChildren() instanceof AggregateConfig) { - LoadBalancerProvider priorityLbProvider = lbRegistry.getProvider(PRIORITY_POLICY_NAME); if (childLb == null) { - childLb = priorityLbProvider.newLoadBalancer(helper); + childLb = lbRegistry.getProvider(PRIORITY_POLICY_NAME).newLoadBalancer(helper); } Map priorityChildConfigs = new HashMap<>(); - for (String childCluster: requireNonNull( - clusterConfig.getClusterResource().prioritizedClusterNames())) { + List leafClusters = ((AggregateConfig) clusterConfig.getChildren()).getLeafNames(); + for (String childCluster: leafClusters) { priorityChildConfigs.put(childCluster, new PriorityChildConfig( GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( @@ -155,9 +153,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { false)); } childConfig = new PriorityLoadBalancerProvider.PriorityLbConfig( - Collections.unmodifiableMap(priorityChildConfigs), - Collections.unmodifiableList(requireNonNull( - clusterConfig.getClusterResource().prioritizedClusterNames()))); + Collections.unmodifiableMap(priorityChildConfigs), leafClusters); } else { return fail(Status.INTERNAL.withDescription( errorPrefix() + "Unexpected cluster children type: " diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index 23a2ad275e2..69230a0a661 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -414,19 +414,51 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() { String cluster1 = "cluster-01.googleapis.com"; String cluster2 = "cluster-02.googleapis.com"; + String cluster3 = "cluster-03.googleapis.com"; + String cluster4 = "cluster-04.googleapis.com"; controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of( - // CLUSTER (aggr.) -> [cluster1 (EDS), cluster2 (EDS)] + // CLUSTER (aggr.) -> [cluster1 (aggr.), cluster2 (logical DNS), cluster3 (EDS)] CLUSTER, Cluster.newBuilder() - .setName(CLUSTER) - .setClusterType(Cluster.CustomClusterType.newBuilder() - .setName("envoy.clusters.aggregate") - .setTypedConfig(Any.pack(ClusterConfig.newBuilder() - .addClusters(cluster1) - .addClusters(cluster2) - .build()))) - .build(), - cluster1, EDS_CLUSTER.toBuilder().setName(cluster1).build(), - cluster2, EDS_CLUSTER.toBuilder().setName(cluster2).build())); + .setName(CLUSTER) + .setClusterType(Cluster.CustomClusterType.newBuilder() + .setName("envoy.clusters.aggregate") + .setTypedConfig(Any.pack(ClusterConfig.newBuilder() + .addClusters(cluster1) + .addClusters(cluster2) + .addClusters(cluster3) + .build()))) + .setLbPolicy(Cluster.LbPolicy.RING_HASH) + .build(), + // cluster1 (aggr.) -> [cluster3 (EDS), cluster4 (EDS)] + cluster1, Cluster.newBuilder() + .setName(cluster1) + .setClusterType(Cluster.CustomClusterType.newBuilder() + .setName("envoy.clusters.aggregate") + .setTypedConfig(Any.pack(ClusterConfig.newBuilder() + .addClusters(cluster3) + .addClusters(cluster4) + .build()))) + .build(), + cluster2, Cluster.newBuilder() + .setName(cluster2) + .setType(Cluster.DiscoveryType.LOGICAL_DNS) + .setLoadAssignment(ClusterLoadAssignment.newBuilder() + .addEndpoints(LocalityLbEndpoints.newBuilder() + .addLbEndpoints(LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("dns.example.com") + .setPortValue(1111))))))) + .build(), + cluster3, EDS_CLUSTER.toBuilder() + .setName(cluster3) + .setCircuitBreakers(CircuitBreakers.newBuilder() + .addThresholds(CircuitBreakers.Thresholds.newBuilder() + .setPriority(RoutingPriority.DEFAULT) + .setMaxRequests(UInt32Value.newBuilder().setValue(100)))) + .build(), + cluster4, EDS_CLUSTER.toBuilder().setName(cluster4).build())); startXdsDepManager(); verify(helper, never()).updateBalancingState(eq(ConnectivityState.TRANSIENT_FAILURE), any()); @@ -435,16 +467,23 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() { assertThat(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME); PriorityLoadBalancerProvider.PriorityLbConfig childLbConfig = (PriorityLoadBalancerProvider.PriorityLbConfig) childBalancer.config; - assertThat(childLbConfig.priorities).hasSize(2); - assertThat(childLbConfig.priorities.get(0)).isEqualTo(cluster1); - assertThat(childLbConfig.priorities.get(1)).isEqualTo(cluster2); - assertThat(childLbConfig.childConfigs).hasSize(2); - PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig1 = - childLbConfig.childConfigs.get(cluster1); - assertThat(childConfig1.toString()).isEqualTo("PriorityChildConfig{childConfig=" + assertThat(childLbConfig.priorities).hasSize(3); + assertThat(childLbConfig.priorities.get(0)).isEqualTo(cluster3); + assertThat(childLbConfig.priorities.get(1)).isEqualTo(cluster4); + assertThat(childLbConfig.priorities.get(2)).isEqualTo(cluster2); + assertThat(childLbConfig.childConfigs).hasSize(3); + PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig3 = + childLbConfig.childConfigs.get(cluster3); + assertThat(childConfig3.toString()).isEqualTo("PriorityChildConfig{childConfig=" + + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" + + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" + + "name=cluster-03.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig4 = + childLbConfig.childConfigs.get(cluster4); + assertThat(childConfig4.toString()).isEqualTo("PriorityChildConfig{childConfig=" + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" - + "name=cluster-01.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + + "name=cluster-04.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig2 = childLbConfig.childConfigs.get(cluster2); assertThat(childConfig2.toString()).isEqualTo("PriorityChildConfig{childConfig=" From fa214047880fc0b72f05018ad41919fa0848bcfc Mon Sep 17 00:00:00 2001 From: deadEternally Date: Wed, 9 Jul 2025 13:38:20 +0530 Subject: [PATCH 15/24] nit --- xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java index 988adbe421b..09307e5e635 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java @@ -243,7 +243,7 @@ private void handleEndpointResourceUpdate() { if (addresses.isEmpty()) { if (endpointNotFound.isOk()) { endpointNotFound = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + cluster); + "No usable endpoint from cluster: " + cluster); } else { endpointNotFound = Status.UNAVAILABLE.withCause(endpointNotFound.getCause()) From 084c51c20347d41b87ab38ddb40c53c2fd81a0b4 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Fri, 11 Jul 2025 16:07:16 +0530 Subject: [PATCH 16/24] Handle cluster type changes by using Graceful switch load balancer as a delegate in CdsLoadbalancer2 --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 41 ++++++++----------- .../io/grpc/xds/CdsLoadBalancer2Test.java | 4 +- 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index 54b5a8e6088..500bf1300c6 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -57,14 +57,15 @@ final class CdsLoadBalancer2 extends LoadBalancer { private final XdsLogger logger; private final Helper helper; private final LoadBalancerRegistry lbRegistry; + private final GracefulSwitchLoadBalancer delegate; // Following fields are effectively final. private String clusterName; private Subscription clusterSubscription; - private LoadBalancer childLb; CdsLoadBalancer2(Helper helper, LoadBalancerRegistry lbRegistry) { this.helper = checkNotNull(helper, "helper"); this.lbRegistry = checkNotNull(lbRegistry, "lbRegistry"); + this.delegate = new GracefulSwitchLoadBalancer(helper); logger = XdsLogger.withLogId(InternalLogId.allocate("cds-lb", helper.getAuthority())); logger.log(XdsLogLevel.INFO, "Created"); } @@ -99,7 +100,7 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { XdsClusterConfig clusterConfig = clusterConfigOr.getValue(); NameResolver.ConfigOrError configOrError; - Object childConfig; + Object gracefulConfig; if (clusterConfig.getChildren() instanceof EndpointConfig) { // The LB policy config is provided in service_config.proto/JSON format. configOrError = @@ -131,17 +132,13 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { result.upstreamTlsContext(), result.filterMetadata()); } - childConfig = new ClusterResolverConfig( + gracefulConfig = GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( + lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME), + new ClusterResolverConfig( instance, configOrError.getConfig(), - clusterConfig.getClusterResource().isHttp11ProxyAvailable()); - if (childLb == null) { - childLb = lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME).newLoadBalancer(helper); - } + clusterConfig.getClusterResource().isHttp11ProxyAvailable())); } else if (clusterConfig.getChildren() instanceof AggregateConfig) { - if (childLb == null) { - childLb = lbRegistry.getProvider(PRIORITY_POLICY_NAME).newLoadBalancer(helper); - } Map priorityChildConfigs = new HashMap<>(); List leafClusters = ((AggregateConfig) clusterConfig.getChildren()).getLeafNames(); for (String childCluster: leafClusters) { @@ -152,23 +149,25 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { new CdsConfig(childCluster)), false)); } - childConfig = new PriorityLoadBalancerProvider.PriorityLbConfig( - Collections.unmodifiableMap(priorityChildConfigs), leafClusters); + gracefulConfig = GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig( + lbRegistry.getProvider(PRIORITY_POLICY_NAME), + new PriorityLoadBalancerProvider.PriorityLbConfig( + Collections.unmodifiableMap(priorityChildConfigs), leafClusters)); } else { return fail(Status.INTERNAL.withDescription( errorPrefix() + "Unexpected cluster children type: " + clusterConfig.getChildren().getClass())); } - return childLb.acceptResolvedAddresses( - resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(childConfig).build()); + return delegate.acceptResolvedAddresses( + resolvedAddresses.toBuilder().setLoadBalancingPolicyConfig(gracefulConfig).build()); } @Override public void handleNameResolutionError(Status error) { logger.log(XdsLogLevel.WARNING, "Received name resolution error: {0}", error); - if (childLb != null) { - childLb.handleNameResolutionError(error); + if (delegate != null) { + delegate.handleNameResolutionError(error); } else { helper.updateBalancingState( TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(error))); @@ -178,10 +177,7 @@ public void handleNameResolutionError(Status error) { @Override public void shutdown() { logger.log(XdsLogLevel.INFO, "Shutdown"); - if (childLb != null) { - childLb.shutdown(); - childLb = null; - } + delegate.shutdown(); if (clusterSubscription != null) { clusterSubscription.close(); clusterSubscription = null; @@ -190,10 +186,7 @@ public void shutdown() { @CheckReturnValue // don't forget to return up the stack after the fail call private Status fail(Status error) { - if (childLb != null) { - childLb.shutdown(); - childLb = null; - } + delegate.shutdown(); helper.updateBalancingState( TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(error))); return Status.OK; // XdsNameResolver isn't a polling NR, so this value doesn't matter diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index 69230a0a661..dcb6a7e303c 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -617,8 +617,8 @@ public void handleNameResolutionErrorFromUpstream_afterChildLbCreated_fallThroug loadBalancer.handleNameResolutionError(Status.UNAVAILABLE.withDescription("unreachable")); assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE); assertThat(childBalancer.upstreamError.getDescription()).isEqualTo("unreachable"); - verify(helper, never()).updateBalancingState( - any(ConnectivityState.class), any(SubchannelPicker.class)); + verify(helper).updateBalancingState( + eq(ConnectivityState.CONNECTING), any(SubchannelPicker.class)); } @Test From f2bfa63006e1840de205609fc61e1e4db2c18b10 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Fri, 11 Jul 2025 16:20:40 +0530 Subject: [PATCH 17/24] Fix test --- .../java/io/grpc/xds/ClusterResolverLoadBalancerTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index b6b28d90134..c6b65d24b9d 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -661,7 +661,7 @@ public void onlyEdsClusters_resourceNeverExist_returnErrorPicker() { assertPicker( pickerCaptor.getValue(), Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + CLUSTER1), + "No usable endpoint from cluster: " + CLUSTER1), null); } @@ -690,7 +690,7 @@ public void edsCluster_resourcesRevoked_shutDownChildLbPolicy() { verify(helper).updateBalancingState( eq(ConnectivityState.TRANSIENT_FAILURE), pickerCaptor.capture()); Status expectedError = Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + CLUSTER1); + "No usable endpoint from cluster: " + CLUSTER1); assertPicker(pickerCaptor.getValue(), expectedError, null); } @@ -789,7 +789,7 @@ public void handleEdsResource_noHealthyEndpoint() { assertPicker( pickerCaptor.getValue(), Status.UNAVAILABLE.withDescription( - "No usable endpoint from cluster(s): " + CLUSTER1), + "No usable endpoint from cluster: " + CLUSTER1), null); } From 7abbc4a977ef9cbee2fd85cce2199eb1d7f1ab23 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Fri, 18 Jul 2025 17:41:59 +0530 Subject: [PATCH 18/24] Review comments. --- .../java/io/grpc/xds/CdsLoadBalancer2.java | 3 ++- .../io/grpc/xds/CdsLoadBalancer2Test.java | 21 ++++++++----------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index 500bf1300c6..f8975ce7828 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -57,7 +57,7 @@ final class CdsLoadBalancer2 extends LoadBalancer { private final XdsLogger logger; private final Helper helper; private final LoadBalancerRegistry lbRegistry; - private final GracefulSwitchLoadBalancer delegate; + private GracefulSwitchLoadBalancer delegate; // Following fields are effectively final. private String clusterName; private Subscription clusterSubscription; @@ -182,6 +182,7 @@ public void shutdown() { clusterSubscription.close(); clusterSubscription = null; } + delegate = new GracefulSwitchLoadBalancer(helper); } @CheckReturnValue // don't forget to return up the stack after the fail call diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index dcb6a7e303c..e5249eba00b 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -474,22 +474,19 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() { assertThat(childLbConfig.childConfigs).hasSize(3); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig3 = childLbConfig.childConfigs.get(cluster3); - assertThat(childConfig3.toString()).isEqualTo("PriorityChildConfig{childConfig=" - + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" - + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" - + "name=cluster-03.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + assertThat( + GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig3.childConfig).getPolicyName()) + .isEqualTo("cds_experimental"); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig4 = childLbConfig.childConfigs.get(cluster4); - assertThat(childConfig4.toString()).isEqualTo("PriorityChildConfig{childConfig=" - + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" - + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" - + "name=cluster-04.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + assertThat( + GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig4.childConfig).getPolicyName()) + .isEqualTo("cds_experimental"); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig2 = childLbConfig.childConfigs.get(cluster2); - assertThat(childConfig2.toString()).isEqualTo("PriorityChildConfig{childConfig=" - + "GracefulSwitchLoadBalancer.Config{childFactory=CdsLoadBalancerProvider{" - + "policy=cds_experimental, priority=5, available=true}, childConfig=CdsConfig{" - + "name=cluster-02.googleapis.com, isDynamic=false}}, ignoreReresolution=false}"); + assertThat( + GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig2.childConfig).getPolicyName()) + .isEqualTo("cds_experimental"); } @Test From 7c16de891e59d24819e8590edcc8227f1f6f9f44 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Fri, 18 Jul 2025 17:53:33 +0530 Subject: [PATCH 19/24] Revert indendation changes done by IDE in unchanged lines. --- .../io/grpc/xds/CdsLoadBalancer2Test.java | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index e5249eba00b..435289e6189 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -419,47 +419,47 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() { controlPlaneService.setXdsConfig(ADS_TYPE_URL_CDS, ImmutableMap.of( // CLUSTER (aggr.) -> [cluster1 (aggr.), cluster2 (logical DNS), cluster3 (EDS)] CLUSTER, Cluster.newBuilder() - .setName(CLUSTER) - .setClusterType(Cluster.CustomClusterType.newBuilder() - .setName("envoy.clusters.aggregate") - .setTypedConfig(Any.pack(ClusterConfig.newBuilder() - .addClusters(cluster1) - .addClusters(cluster2) - .addClusters(cluster3) - .build()))) - .setLbPolicy(Cluster.LbPolicy.RING_HASH) - .build(), + .setName(CLUSTER) + .setClusterType(Cluster.CustomClusterType.newBuilder() + .setName("envoy.clusters.aggregate") + .setTypedConfig(Any.pack(ClusterConfig.newBuilder() + .addClusters(cluster1) + .addClusters(cluster2) + .addClusters(cluster3) + .build()))) + .setLbPolicy(Cluster.LbPolicy.RING_HASH) + .build(), // cluster1 (aggr.) -> [cluster3 (EDS), cluster4 (EDS)] cluster1, Cluster.newBuilder() - .setName(cluster1) - .setClusterType(Cluster.CustomClusterType.newBuilder() - .setName("envoy.clusters.aggregate") - .setTypedConfig(Any.pack(ClusterConfig.newBuilder() - .addClusters(cluster3) - .addClusters(cluster4) - .build()))) - .build(), + .setName(cluster1) + .setClusterType(Cluster.CustomClusterType.newBuilder() + .setName("envoy.clusters.aggregate") + .setTypedConfig(Any.pack(ClusterConfig.newBuilder() + .addClusters(cluster3) + .addClusters(cluster4) + .build()))) + .build(), cluster2, Cluster.newBuilder() - .setName(cluster2) - .setType(Cluster.DiscoveryType.LOGICAL_DNS) - .setLoadAssignment(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .addLbEndpoints(LbEndpoint.newBuilder() - .setEndpoint(Endpoint.newBuilder() - .setAddress(Address.newBuilder() - .setSocketAddress(SocketAddress.newBuilder() - .setAddress("dns.example.com") - .setPortValue(1111))))))) - .build(), + .setName(cluster2) + .setType(Cluster.DiscoveryType.LOGICAL_DNS) + .setLoadAssignment(ClusterLoadAssignment.newBuilder() + .addEndpoints(LocalityLbEndpoints.newBuilder() + .addLbEndpoints(LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("dns.example.com") + .setPortValue(1111))))))) + .build(), cluster3, EDS_CLUSTER.toBuilder() .setName(cluster3) .setCircuitBreakers(CircuitBreakers.newBuilder() .addThresholds(CircuitBreakers.Thresholds.newBuilder() - .setPriority(RoutingPriority.DEFAULT) - .setMaxRequests(UInt32Value.newBuilder().setValue(100)))) + .setPriority(RoutingPriority.DEFAULT) + .setMaxRequests(UInt32Value.newBuilder().setValue(100)))) .build(), cluster4, EDS_CLUSTER.toBuilder().setName(cluster4).build())); - startXdsDepManager(); + startXdsDepManager(); verify(helper, never()).updateBalancingState(eq(ConnectivityState.TRANSIENT_FAILURE), any()); assertThat(childBalancers).hasSize(1); From f6afb635f976247488e6d46bf42d6a83341f2fe2 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Tue, 22 Jul 2025 10:54:14 +0530 Subject: [PATCH 20/24] A map for ClusterState is not required in ClusterResolverLoadBalancer which now holds only a single cluster's state. --- .../grpc/xds/ClusterResolverLoadBalancer.java | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java index 09307e5e635..e333c46750c 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancer.java @@ -168,7 +168,7 @@ public LoadBalancer newLoadBalancer(Helper helper) { */ private final class ClusterResolverLbState extends LoadBalancer { private final Helper helper; - private final Map clusterStates = new HashMap<>(); + private ClusterState clusterState; private String cluster; private Object endpointLbConfig; private ResolvedAddresses resolvedAddresses; @@ -187,18 +187,16 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) { endpointLbConfig = config.lbConfig; DiscoveryMechanism instance = config.discoveryMechanism; cluster = instance.cluster; - ClusterState state; if (instance.type == DiscoveryMechanism.Type.EDS) { - state = new EdsClusterState(instance.cluster, instance.edsServiceName, + clusterState = new EdsClusterState(instance.cluster, instance.edsServiceName, instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext, instance.filterMetadata, instance.outlierDetection); } else { // logical DNS - state = new LogicalDnsClusterState(instance.cluster, instance.dnsHostName, + clusterState = new LogicalDnsClusterState(instance.cluster, instance.dnsHostName, instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext, instance.filterMetadata); } - clusterStates.put(instance.cluster, state); - state.start(); + clusterState.start(); return Status.OK; } @@ -214,9 +212,7 @@ public void handleNameResolutionError(Status error) { @Override public void shutdown() { - for (ClusterState state : clusterStates.values()) { - state.shutdown(); - } + clusterState.shutdown(); if (childLb != null) { childLb.shutdown(); } @@ -228,17 +224,16 @@ private void handleEndpointResourceUpdate() { List priorities = new ArrayList<>(); // totally ordered priority list Status endpointNotFound = Status.OK; - ClusterState state = clusterStates.get(cluster); // Propagate endpoints to the child LB policy only after all clusters have been resolved. - if (!state.resolved && state.status.isOk()) { + if (!clusterState.resolved && clusterState.status.isOk()) { return; } - if (state.result != null) { - addresses.addAll(state.result.addresses); - priorityChildConfigs.putAll(state.result.priorityChildConfigs); - priorities.addAll(state.result.priorities); + if (clusterState.result != null) { + addresses.addAll(clusterState.result.addresses); + priorityChildConfigs.putAll(clusterState.result.priorityChildConfigs); + priorities.addAll(clusterState.result.priorities); } else { - endpointNotFound = state.status; + endpointNotFound = clusterState.status; } if (addresses.isEmpty()) { if (endpointNotFound.isOk()) { @@ -271,13 +266,12 @@ private void handleEndpointResourceUpdate() { } private void handleEndpointResolutionError() { - ClusterState state = clusterStates.get(cluster); - if (!state.status.isOk()) { + if (!clusterState.status.isOk()) { if (childLb != null) { - childLb.handleNameResolutionError(state.status); + childLb.handleNameResolutionError(clusterState.status); } else { helper.updateBalancingState( - TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(state.status))); + TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(clusterState.status))); } } } @@ -294,10 +288,8 @@ private RefreshableHelper(Helper delegate) { @Override public void refreshNameResolution() { - for (ClusterState state : clusterStates.values()) { - if (state instanceof LogicalDnsClusterState) { - ((LogicalDnsClusterState) state).refresh(); - } + if (clusterState instanceof LogicalDnsClusterState) { + ((LogicalDnsClusterState) clusterState).refresh(); } } From e2a7382b386b37a5cb78483ddeed6694a0576770 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Tue, 29 Jul 2025 14:28:37 +0530 Subject: [PATCH 21/24] Reinstantiate delegate after shutdown. --- xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java index f8975ce7828..87963476265 100644 --- a/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/CdsLoadBalancer2.java @@ -178,11 +178,11 @@ public void handleNameResolutionError(Status error) { public void shutdown() { logger.log(XdsLogLevel.INFO, "Shutdown"); delegate.shutdown(); + delegate = new GracefulSwitchLoadBalancer(helper); if (clusterSubscription != null) { clusterSubscription.close(); clusterSubscription = null; } - delegate = new GracefulSwitchLoadBalancer(helper); } @CheckReturnValue // don't forget to return up the stack after the fail call From 8c1199d9f44b2ab5c81aaff48616a5f88ebf6ca9 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Tue, 29 Jul 2025 15:29:28 +0530 Subject: [PATCH 22/24] Fix problem after merge. --- .../java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java index 89ad6c26b5f..48101cd9c54 100644 --- a/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java @@ -88,7 +88,7 @@ boolean isHttp11ProxyAvailable() { @Override public int hashCode() { - return Objects.hash(discoveryMechanisms, lbConfig, isHttp11ProxyAvailable); + return Objects.hash(discoveryMechanism, lbConfig, isHttp11ProxyAvailable); } @Override @@ -100,7 +100,7 @@ public boolean equals(Object o) { return false; } ClusterResolverConfig that = (ClusterResolverConfig) o; - return discoveryMechanisms.equals(that.discoveryMechanisms) + return discoveryMechanism.equals(that.discoveryMechanism) && lbConfig.equals(that.lbConfig) && isHttp11ProxyAvailable == that.isHttp11ProxyAvailable; } From 24910d80abc75b178d32c40dd38ecd81931a923e Mon Sep 17 00:00:00 2001 From: deadEternally Date: Tue, 29 Jul 2025 15:37:30 +0530 Subject: [PATCH 23/24] Fix problem after merge. --- .../io/grpc/xds/ClusterResolverLoadBalancerTest.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java index ce99f9abda5..982677d24da 100644 --- a/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterResolverLoadBalancerTest.java @@ -1088,19 +1088,17 @@ public void config_equalsTester() { new EqualsTester() .addEqualityGroup( new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), leastRequest, false), + edsDiscoveryMechanism1, leastRequest, false), new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), leastRequest, false)) + edsDiscoveryMechanism1, leastRequest, false)) .addEqualityGroup(new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), roundRobin, false)) + edsDiscoveryMechanism1, roundRobin, false)) .addEqualityGroup(new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanism1), leastRequest, true)) + edsDiscoveryMechanism1, leastRequest, true)) .addEqualityGroup(new ClusterResolverConfig( - Collections.singletonList(edsDiscoveryMechanismWithOutlierDetection), + edsDiscoveryMechanismWithOutlierDetection, leastRequest, false)) - .addEqualityGroup(new ClusterResolverConfig( - Arrays.asList(edsDiscoveryMechanism1, edsDiscoveryMechanism2), leastRequest, false)) .testEquals(); } From 6c750180ea7eab3c32d51156edb423f3448dd833 Mon Sep 17 00:00:00 2001 From: deadEternally Date: Tue, 29 Jul 2025 16:09:16 +0530 Subject: [PATCH 24/24] Fix style errors. --- .../test/java/io/grpc/xds/CdsLoadBalancer2Test.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java index 435289e6189..2059022c203 100644 --- a/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/CdsLoadBalancer2Test.java @@ -459,7 +459,7 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() { .setMaxRequests(UInt32Value.newBuilder().setValue(100)))) .build(), cluster4, EDS_CLUSTER.toBuilder().setName(cluster4).build())); - startXdsDepManager(); + startXdsDepManager(); verify(helper, never()).updateBalancingState(eq(ConnectivityState.TRANSIENT_FAILURE), any()); assertThat(childBalancers).hasSize(1); @@ -475,17 +475,20 @@ public void discoverAggregateCluster_createsPriorityLbPolicy() { PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig3 = childLbConfig.childConfigs.get(cluster3); assertThat( - GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig3.childConfig).getPolicyName()) + GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig3.childConfig) + .getPolicyName()) .isEqualTo("cds_experimental"); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig4 = childLbConfig.childConfigs.get(cluster4); assertThat( - GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig4.childConfig).getPolicyName()) + GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig4.childConfig) + .getPolicyName()) .isEqualTo("cds_experimental"); PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig2 = childLbConfig.childConfigs.get(cluster2); assertThat( - GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig2.childConfig).getPolicyName()) + GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig2.childConfig) + .getPolicyName()) .isEqualTo("cds_experimental"); }