mirror of https://github.com/grpc/grpc-java.git
Xds: Aggregate cluster fixes (A75) (#12186)
Instead of representing an aggregate cluster as a single cluster whose priorities come from different underlying clusters, represent an aggregate cluster as an instance of a priority LB policy where each child is a cds LB policy for the underlying cluster.
This commit is contained in:
parent
c3ef1ab034
commit
7e982e48a1
|
|
@ -18,10 +18,10 @@ package io.grpc.xds;
|
|||
|
||||
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 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,6 +33,7 @@ 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;
|
||||
|
|
@ -41,10 +42,11 @@ import io.grpc.xds.XdsConfig.XdsClusterConfig.AggregateConfig;
|
|||
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;
|
||||
|
||||
/**
|
||||
* Load balancer for cds_experimental LB policy. One instance per top-level cluster.
|
||||
|
|
@ -55,19 +57,15 @@ final class CdsLoadBalancer2 extends LoadBalancer {
|
|||
private final XdsLogger logger;
|
||||
private final Helper helper;
|
||||
private final LoadBalancerRegistry lbRegistry;
|
||||
private GracefulSwitchLoadBalancer delegate;
|
||||
// Following fields are effectively final.
|
||||
private String clusterName;
|
||||
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.delegate = new GracefulSwitchLoadBalancer(helper);
|
||||
logger = XdsLogger.withLogId(InternalLogId.allocate("cds-lb", helper.getAuthority()));
|
||||
logger.log(XdsLogLevel.INFO, "Created");
|
||||
}
|
||||
|
|
@ -91,7 +89,7 @@ final class CdsLoadBalancer2 extends LoadBalancer {
|
|||
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,42 +98,25 @@ final class CdsLoadBalancer2 extends LoadBalancer {
|
|||
return fail(clusterConfigOr.getStatus());
|
||||
}
|
||||
XdsClusterConfig clusterConfig = clusterConfigOr.getValue();
|
||||
List<String> 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<DiscoveryMechanism> instances = new ArrayList<>();
|
||||
for (String leafName : leafNames) {
|
||||
StatusOr<XdsClusterConfig> leafConfigOr = xdsConfig.getClusters().get(leafName);
|
||||
if (!leafConfigOr.hasValue()) {
|
||||
noneFoundError = leafConfigOr.getStatus();
|
||||
continue;
|
||||
NameResolver.ConfigOrError configOrError;
|
||||
Object gracefulConfig;
|
||||
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()));
|
||||
}
|
||||
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();
|
||||
CdsUpdate result = clusterConfig.getClusterResource();
|
||||
DiscoveryMechanism instance;
|
||||
if (result.clusterType() == ClusterType.EDS) {
|
||||
instance = DiscoveryMechanism.forEds(
|
||||
leafName,
|
||||
clusterName,
|
||||
result.edsServiceName(),
|
||||
result.lrsServerInfo(),
|
||||
result.maxConcurrentRequests(),
|
||||
|
|
@ -144,45 +125,49 @@ final class CdsLoadBalancer2 extends LoadBalancer {
|
|||
result.outlierDetection());
|
||||
} else {
|
||||
instance = DiscoveryMechanism.forLogicalDns(
|
||||
leafName,
|
||||
clusterName,
|
||||
result.dnsHostName(),
|
||||
result.lrsServerInfo(),
|
||||
result.maxConcurrentRequests(),
|
||||
result.upstreamTlsContext(),
|
||||
result.filterMetadata());
|
||||
}
|
||||
instances.add(instance);
|
||||
}
|
||||
if (instances.isEmpty()) {
|
||||
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
|
||||
gracefulConfig = GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig(
|
||||
lbRegistry.getProvider(CLUSTER_RESOLVER_POLICY_NAME),
|
||||
new ClusterResolverConfig(
|
||||
instance,
|
||||
configOrError.getConfig(),
|
||||
clusterConfig.getClusterResource().isHttp11ProxyAvailable()));
|
||||
} else if (clusterConfig.getChildren() instanceof AggregateConfig) {
|
||||
Map<String, PriorityChildConfig> priorityChildConfigs = new HashMap<>();
|
||||
List<String> leafClusters = ((AggregateConfig) clusterConfig.getChildren()).getLeafNames();
|
||||
for (String childCluster: leafClusters) {
|
||||
priorityChildConfigs.put(childCluster,
|
||||
new PriorityChildConfig(
|
||||
GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig(
|
||||
lbRegistry.getProvider(CDS_POLICY_NAME),
|
||||
new CdsConfig(childCluster)),
|
||||
false));
|
||||
}
|
||||
gracefulConfig = GracefulSwitchLoadBalancer.createLoadBalancingPolicyConfig(
|
||||
lbRegistry.getProvider(PRIORITY_POLICY_NAME),
|
||||
new PriorityLoadBalancerProvider.PriorityLbConfig(
|
||||
Collections.unmodifiableMap(priorityChildConfigs), leafClusters));
|
||||
} else {
|
||||
return fail(Status.INTERNAL.withDescription(
|
||||
errorPrefix() + "Unable to parse the LB config: " + configOrError.getError()));
|
||||
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());
|
||||
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)));
|
||||
|
|
@ -192,10 +177,8 @@ final class CdsLoadBalancer2 extends LoadBalancer {
|
|||
@Override
|
||||
public void shutdown() {
|
||||
logger.log(XdsLogLevel.INFO, "Shutdown");
|
||||
if (childLb != null) {
|
||||
childLb.shutdown();
|
||||
childLb = null;
|
||||
}
|
||||
delegate.shutdown();
|
||||
delegate = new GracefulSwitchLoadBalancer(helper);
|
||||
if (clusterSubscription != null) {
|
||||
clusterSubscription.close();
|
||||
clusterSubscription = null;
|
||||
|
|
@ -204,10 +187,7 @@ final class CdsLoadBalancer2 extends LoadBalancer {
|
|||
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import io.grpc.Internal;
|
|||
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 class CdsLoadBalancerProvider extends LoadBalancerProvider {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -168,8 +168,8 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
|
|||
*/
|
||||
private final class ClusterResolverLbState extends LoadBalancer {
|
||||
private final Helper helper;
|
||||
private final List<String> clusters = new ArrayList<>();
|
||||
private final Map<String, ClusterState> clusterStates = new HashMap<>();
|
||||
private ClusterState clusterState;
|
||||
private String cluster;
|
||||
private Object endpointLbConfig;
|
||||
private ResolvedAddresses resolvedAddresses;
|
||||
private LoadBalancer childLb;
|
||||
|
|
@ -185,21 +185,18 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
|
|||
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;
|
||||
cluster = instance.cluster;
|
||||
if (instance.type == DiscoveryMechanism.Type.EDS) {
|
||||
clusterState = new EdsClusterState(instance.cluster, instance.edsServiceName,
|
||||
instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext,
|
||||
instance.filterMetadata, instance.outlierDetection);
|
||||
} else { // logical DNS
|
||||
clusterState = new LogicalDnsClusterState(instance.cluster, instance.dnsHostName,
|
||||
instance.lrsServerInfo, instance.maxConcurrentRequests, instance.tlsContext,
|
||||
instance.filterMetadata);
|
||||
}
|
||||
clusterState.start();
|
||||
return Status.OK;
|
||||
}
|
||||
|
||||
|
|
@ -215,9 +212,7 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
|
|||
|
||||
@Override
|
||||
public void shutdown() {
|
||||
for (ClusterState state : clusterStates.values()) {
|
||||
state.shutdown();
|
||||
}
|
||||
clusterState.shutdown();
|
||||
if (childLb != null) {
|
||||
childLb.shutdown();
|
||||
}
|
||||
|
|
@ -229,24 +224,21 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
|
|||
List<String> 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;
|
||||
}
|
||||
// Propagate endpoints to the child LB policy only after all clusters have been resolved.
|
||||
if (!clusterState.resolved && clusterState.status.isOk()) {
|
||||
return;
|
||||
}
|
||||
if (clusterState.result != null) {
|
||||
addresses.addAll(clusterState.result.addresses);
|
||||
priorityChildConfigs.putAll(clusterState.result.priorityChildConfigs);
|
||||
priorities.addAll(clusterState.result.priorities);
|
||||
} else {
|
||||
endpointNotFound = clusterState.status;
|
||||
}
|
||||
if (addresses.isEmpty()) {
|
||||
if (endpointNotFound.isOk()) {
|
||||
endpointNotFound = Status.UNAVAILABLE.withDescription(
|
||||
"No usable endpoint from cluster(s): " + clusters);
|
||||
"No usable endpoint from cluster: " + cluster);
|
||||
} else {
|
||||
endpointNotFound =
|
||||
Status.UNAVAILABLE.withCause(endpointNotFound.getCause())
|
||||
|
|
@ -274,22 +266,12 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
|
|||
}
|
||||
|
||||
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) {
|
||||
if (!clusterState.status.isOk()) {
|
||||
if (childLb != null) {
|
||||
childLb.handleNameResolutionError(error);
|
||||
childLb.handleNameResolutionError(clusterState.status);
|
||||
} else {
|
||||
helper.updateBalancingState(
|
||||
TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(error)));
|
||||
TRANSIENT_FAILURE, new FixedResultPicker(PickResult.withError(clusterState.status)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -306,10 +288,8 @@ final class ClusterResolverLoadBalancer extends LoadBalancer {
|
|||
|
||||
@Override
|
||||
public void refreshNameResolution() {
|
||||
for (ClusterState state : clusterStates.values()) {
|
||||
if (state instanceof LogicalDnsClusterState) {
|
||||
((LogicalDnsClusterState) state).refresh();
|
||||
}
|
||||
if (clusterState instanceof LogicalDnsClusterState) {
|
||||
((LogicalDnsClusterState) clusterState).refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ import io.grpc.Status;
|
|||
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;
|
||||
|
|
@ -70,15 +69,15 @@ public final class ClusterResolverLoadBalancerProvider extends LoadBalancerProvi
|
|||
}
|
||||
|
||||
static final class ClusterResolverConfig {
|
||||
// Ordered list of clusters to be resolved.
|
||||
final List<DiscoveryMechanism> discoveryMechanisms;
|
||||
// Cluster to be resolved.
|
||||
final DiscoveryMechanism discoveryMechanism;
|
||||
// GracefulSwitch configuration
|
||||
final Object lbConfig;
|
||||
private final boolean isHttp11ProxyAvailable;
|
||||
|
||||
ClusterResolverConfig(List<DiscoveryMechanism> discoveryMechanisms, Object lbConfig,
|
||||
ClusterResolverConfig(DiscoveryMechanism discoveryMechanism, Object lbConfig,
|
||||
boolean isHttp11ProxyAvailable) {
|
||||
this.discoveryMechanisms = checkNotNull(discoveryMechanisms, "discoveryMechanisms");
|
||||
this.discoveryMechanism = checkNotNull(discoveryMechanism, "discoveryMechanism");
|
||||
this.lbConfig = checkNotNull(lbConfig, "lbConfig");
|
||||
this.isHttp11ProxyAvailable = isHttp11ProxyAvailable;
|
||||
}
|
||||
|
|
@ -89,7 +88,7 @@ public final class ClusterResolverLoadBalancerProvider extends LoadBalancerProvi
|
|||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(discoveryMechanisms, lbConfig, isHttp11ProxyAvailable);
|
||||
return Objects.hash(discoveryMechanism, lbConfig, isHttp11ProxyAvailable);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -101,7 +100,7 @@ public final class ClusterResolverLoadBalancerProvider extends LoadBalancerProvi
|
|||
return false;
|
||||
}
|
||||
ClusterResolverConfig that = (ClusterResolverConfig) o;
|
||||
return discoveryMechanisms.equals(that.discoveryMechanisms)
|
||||
return discoveryMechanism.equals(that.discoveryMechanism)
|
||||
&& lbConfig.equals(that.lbConfig)
|
||||
&& isHttp11ProxyAvailable == that.isHttp11ProxyAvailable;
|
||||
}
|
||||
|
|
@ -109,7 +108,7 @@ public final class ClusterResolverLoadBalancerProvider extends LoadBalancerProvi
|
|||
@Override
|
||||
public String toString() {
|
||||
return MoreObjects.toStringHelper(this)
|
||||
.add("discoveryMechanisms", discoveryMechanisms)
|
||||
.add("discoveryMechanism", discoveryMechanism)
|
||||
.add("lbConfig", lbConfig)
|
||||
.add("isHttp11ProxyAvailable", isHttp11ProxyAvailable)
|
||||
.toString();
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package io.grpc.xds;
|
|||
|
||||
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.ArgumentMatchers.eq;
|
|||
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;
|
||||
|
|
@ -157,7 +159,9 @@ public class CdsLoadBalancer2Test {
|
|||
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")
|
||||
|
|
@ -169,6 +173,8 @@ public class CdsLoadBalancer2Test {
|
|||
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)
|
||||
|
|
@ -246,13 +252,12 @@ public class CdsLoadBalancer2Test {
|
|||
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
|
||||
assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME);
|
||||
ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config;
|
||||
assertThat(childLbConfig.discoveryMechanisms).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)))));
|
||||
assertThat(childLbConfig.discoveryMechanism).isEqualTo(
|
||||
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");
|
||||
|
|
@ -296,11 +301,10 @@ public class CdsLoadBalancer2Test {
|
|||
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
|
||||
assertThat(childBalancer.name).isEqualTo(CLUSTER_RESOLVER_POLICY_NAME);
|
||||
ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config;
|
||||
assertThat(childLbConfig.discoveryMechanisms).isEqualTo(
|
||||
Arrays.asList(
|
||||
DiscoveryMechanism.forLogicalDns(
|
||||
CLUSTER, "dns.example.com:1111", lrsServerInfo, 100L, upstreamTlsContext,
|
||||
Collections.emptyMap())));
|
||||
assertThat(childLbConfig.discoveryMechanism).isEqualTo(
|
||||
DiscoveryMechanism.forLogicalDns(
|
||||
CLUSTER, "dns.example.com:1111", lrsServerInfo, 100L, upstreamTlsContext,
|
||||
Collections.emptyMap()));
|
||||
assertThat(
|
||||
GracefulSwitchLoadBalancerAccessor.getChildProvider(childLbConfig.lbConfig).getPolicyName())
|
||||
.isEqualTo("wrr_locality_experimental");
|
||||
|
|
@ -332,10 +336,9 @@ public class CdsLoadBalancer2Test {
|
|||
assertThat(childBalancers).hasSize(1);
|
||||
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
|
||||
ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config;
|
||||
assertThat(childLbConfig.discoveryMechanisms).isEqualTo(
|
||||
Arrays.asList(
|
||||
assertThat(childLbConfig.discoveryMechanism).isEqualTo(
|
||||
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()
|
||||
|
|
@ -348,10 +351,9 @@ public class CdsLoadBalancer2Test {
|
|||
assertThat(childBalancers).hasSize(1);
|
||||
childBalancer = Iterables.getOnlyElement(childBalancers);
|
||||
childLbConfig = (ClusterResolverConfig) childBalancer.config;
|
||||
assertThat(childLbConfig.discoveryMechanisms).isEqualTo(
|
||||
Arrays.asList(
|
||||
assertThat(childLbConfig.discoveryMechanism).isEqualTo(
|
||||
DiscoveryMechanism.forEds(
|
||||
CLUSTER, EDS_SERVICE_NAME, null, 200L, null, Collections.emptyMap(), null)));
|
||||
CLUSTER, EDS_SERVICE_NAME, null, 200L, null, Collections.emptyMap(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -363,10 +365,9 @@ public class CdsLoadBalancer2Test {
|
|||
assertThat(childBalancers).hasSize(1);
|
||||
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
|
||||
ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config;
|
||||
assertThat(childLbConfig.discoveryMechanisms).isEqualTo(
|
||||
Arrays.asList(
|
||||
assertThat(childLbConfig.discoveryMechanism).isEqualTo(
|
||||
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());
|
||||
|
||||
|
|
@ -395,10 +396,9 @@ public class CdsLoadBalancer2Test {
|
|||
assertThat(childBalancers).hasSize(1);
|
||||
FakeLoadBalancer childBalancer = Iterables.getOnlyElement(childBalancers);
|
||||
ClusterResolverConfig childLbConfig = (ClusterResolverConfig) childBalancer.config;
|
||||
assertThat(childLbConfig.discoveryMechanisms).isEqualTo(
|
||||
Arrays.asList(
|
||||
assertThat(childLbConfig.discoveryMechanism).isEqualTo(
|
||||
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();
|
||||
|
|
@ -406,7 +406,12 @@ public class CdsLoadBalancer2Test {
|
|||
}
|
||||
|
||||
@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";
|
||||
String cluster3 = "cluster-03.googleapis.com";
|
||||
|
|
@ -459,20 +464,77 @@ public class CdsLoadBalancer2Test {
|
|||
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.discoveryMechanisms).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(childBalancer.name).isEqualTo(PRIORITY_POLICY_NAME);
|
||||
PriorityLoadBalancerProvider.PriorityLbConfig childLbConfig =
|
||||
(PriorityLoadBalancerProvider.PriorityLbConfig) childBalancer.config;
|
||||
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(
|
||||
GracefulSwitchLoadBalancerAccessor.getChildProvider(childLbConfig.lbConfig).getPolicyName())
|
||||
.isEqualTo("ring_hash_experimental"); // dominated by top-level cluster's config
|
||||
GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig3.childConfig)
|
||||
.getPolicyName())
|
||||
.isEqualTo("cds_experimental");
|
||||
PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig4 =
|
||||
childLbConfig.childConfigs.get(cluster4);
|
||||
assertThat(
|
||||
GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig4.childConfig)
|
||||
.getPolicyName())
|
||||
.isEqualTo("cds_experimental");
|
||||
PriorityLoadBalancerProvider.PriorityLbConfig.PriorityChildConfig childConfig2 =
|
||||
childLbConfig.childConfigs.get(cluster2);
|
||||
assertThat(
|
||||
GracefulSwitchLoadBalancerAccessor.getChildProvider(childConfig2.childConfig)
|
||||
.getPolicyName())
|
||||
.isEqualTo("cds_experimental");
|
||||
}
|
||||
|
||||
@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
|
||||
|
|
@ -500,6 +562,11 @@ public class CdsLoadBalancer2Test {
|
|||
|
||||
@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)]
|
||||
|
|
@ -550,8 +617,8 @@ public class CdsLoadBalancer2Test {
|
|||
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
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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();
|
||||
|
|
@ -311,7 +311,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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();
|
||||
|
|
@ -358,7 +358,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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();
|
||||
|
|
@ -385,7 +385,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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();
|
||||
|
|
@ -404,7 +404,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create(
|
||||
Arrays.asList(
|
||||
LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true,
|
||||
"hostname1", endpointMetadata)),
|
||||
"hostname1", endpointMetadata)),
|
||||
100 /* localityWeight */, 1 /* priority */, localityMetadata);
|
||||
|
||||
xdsClient.deliverClusterLoadAssignment(
|
||||
|
|
@ -432,7 +432,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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();
|
||||
|
|
@ -451,7 +451,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
LocalityLbEndpoints localityLbEndpoints = LocalityLbEndpoints.create(
|
||||
Arrays.asList(
|
||||
LbEndpoint.create(endpoint, 0 /* loadBalancingWeight */, true,
|
||||
"hostname2", endpointMetadata)),
|
||||
"hostname2", endpointMetadata)),
|
||||
100 /* localityWeight */, 1 /* priority */, localityMetadata);
|
||||
|
||||
xdsClient.deliverClusterLoadAssignment(
|
||||
|
|
@ -479,48 +479,36 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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())),
|
||||
"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);
|
||||
|
|
@ -528,12 +516,12 @@ public class ClusterResolverLoadBalancerTest {
|
|||
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())
|
||||
.getPolicyName())
|
||||
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
|
||||
ClusterImplConfig clusterImplConfig1 = (ClusterImplConfig)
|
||||
GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig1.childConfig);
|
||||
|
|
@ -548,7 +536,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
PriorityChildConfig priorityChildConfig2 = priorityLbConfig.childConfigs.get(priority2);
|
||||
assertThat(priorityChildConfig2.ignoreReresolution).isTrue();
|
||||
assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig2.childConfig)
|
||||
.getPolicyName())
|
||||
.getPolicyName())
|
||||
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
|
||||
ClusterImplConfig clusterImplConfig2 = (ClusterImplConfig)
|
||||
GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig2.childConfig);
|
||||
|
|
@ -560,15 +548,6 @@ public class ClusterResolverLoadBalancerTest {
|
|||
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.<DropOverload>emptyList(), WRR_LOCALITY_POLICY_NAME);
|
||||
WrrLocalityConfig wrrLocalityConfig3 = (WrrLocalityConfig)
|
||||
GracefulSwitchLoadBalancerAccessor.getChildConfig(clusterImplConfig1.childConfig);
|
||||
LoadBalancerProvider childProvider3 =
|
||||
|
|
@ -595,7 +574,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
private void verifyEdsPriorityNames(List<String> want,
|
||||
Map<Locality, LocalityLbEndpoints>... 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();
|
||||
|
|
@ -617,7 +596,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
public void edsUpdatePriorityName_twoPriorities() {
|
||||
verifyEdsPriorityNames(Arrays.asList(CLUSTER2 + "[child1]", CLUSTER2 + "[child2]"),
|
||||
ImmutableMap.of(locality1, createEndpoints(1),
|
||||
locality2, createEndpoints(2)
|
||||
locality2, createEndpoints(2)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -653,8 +632,8 @@ public class ClusterResolverLoadBalancerTest {
|
|||
locality3, createEndpoints(3),
|
||||
locality2, createEndpoints(2)),
|
||||
ImmutableMap.of(locality1, createEndpoints(2),
|
||||
locality3, createEndpoints(1),
|
||||
locality2, createEndpoints(1)
|
||||
locality3, createEndpoints(1),
|
||||
locality2, createEndpoints(1)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
@ -662,76 +641,64 @@ public class ClusterResolverLoadBalancerTest {
|
|||
return LocalityLbEndpoints.create(
|
||||
Arrays.asList(
|
||||
LbEndpoint.create(makeAddress("endpoint-addr-1"), 100,
|
||||
true, "hostname1", ImmutableMap.of()),
|
||||
true, "hostname1", ImmutableMap.of()),
|
||||
LbEndpoint.create(makeAddress("endpoint-addr-2"), 100,
|
||||
true, "hostname2", ImmutableMap.of())),
|
||||
true, "hostname2", ImmutableMap.of())),
|
||||
70 /* localityWeight */, priority /* priority */, ImmutableMap.of());
|
||||
}
|
||||
|
||||
@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());
|
||||
assertPicker(
|
||||
pickerCaptor.getValue(),
|
||||
Status.UNAVAILABLE.withDescription(
|
||||
"No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1, CLUSTER2)),
|
||||
"No usable endpoint from cluster: " + CLUSTER1),
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void onlyEdsClusters_allResourcesRevoked_shutDownChildLbPolicy() {
|
||||
public void edsCluster_resourcesRevoked_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())),
|
||||
"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());
|
||||
xdsClient.deliverClusterLoadAssignment(
|
||||
EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints1));
|
||||
xdsClient.deliverClusterLoadAssignment(
|
||||
EDS_SERVICE_NAME2, Collections.singletonMap(locality2, localityLbEndpoints2));
|
||||
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());
|
||||
Status expectedError = Status.UNAVAILABLE.withDescription(
|
||||
"No usable endpoint from cluster(s): " + Arrays.asList(CLUSTER1, CLUSTER2));
|
||||
"No usable endpoint from cluster: " + CLUSTER1);
|
||||
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");
|
||||
|
|
@ -739,9 +706,9 @@ public class ClusterResolverLoadBalancerTest {
|
|||
LocalityLbEndpoints.create(
|
||||
Arrays.asList(
|
||||
LbEndpoint.create(endpoint1, 100, false /* isHealthy */,
|
||||
"hostname1", ImmutableMap.of()),
|
||||
"hostname1", ImmutableMap.of()),
|
||||
LbEndpoint.create(endpoint2, 100, true /* isHealthy */,
|
||||
"hostname2", ImmutableMap.of())),
|
||||
"hostname2", ImmutableMap.of())),
|
||||
10 /* localityWeight */, 1 /* priority */, ImmutableMap.of());
|
||||
xdsClient.deliverClusterLoadAssignment(
|
||||
EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints));
|
||||
|
|
@ -753,19 +720,19 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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())),
|
||||
"hostname1", ImmutableMap.of())),
|
||||
10 /* localityWeight */, 1 /* priority */, ImmutableMap.of());
|
||||
LocalityLbEndpoints localityLbEndpoints2 =
|
||||
LocalityLbEndpoints.create(
|
||||
Collections.singletonList(LbEndpoint.create(endpoint2, 100, true /* isHealthy */,
|
||||
"hostname2", ImmutableMap.of())),
|
||||
"hostname2", ImmutableMap.of())),
|
||||
10 /* localityWeight */, 1 /* priority */, ImmutableMap.of());
|
||||
xdsClient.deliverClusterLoadAssignment(
|
||||
EDS_SERVICE_NAME1,
|
||||
|
|
@ -780,20 +747,20 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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())),
|
||||
"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,
|
||||
|
|
@ -806,7 +773,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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 =
|
||||
|
|
@ -823,7 +790,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
assertPicker(
|
||||
pickerCaptor.getValue(),
|
||||
Status.UNAVAILABLE.withDescription(
|
||||
"No usable endpoint from cluster(s): " + Collections.singleton(CLUSTER1)),
|
||||
"No usable endpoint from cluster: " + CLUSTER1),
|
||||
null);
|
||||
}
|
||||
|
||||
|
|
@ -841,7 +808,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
|
||||
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();
|
||||
|
|
@ -857,7 +824,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
PriorityChildConfig priorityChildConfig = priorityLbConfig.childConfigs.get(priority);
|
||||
assertThat(priorityChildConfig.ignoreReresolution).isFalse();
|
||||
assertThat(GracefulSwitchLoadBalancerAccessor.getChildProvider(priorityChildConfig.childConfig)
|
||||
.getPolicyName())
|
||||
.getPolicyName())
|
||||
.isEqualTo(CLUSTER_IMPL_POLICY_NAME);
|
||||
ClusterImplConfig clusterImplConfig = (ClusterImplConfig)
|
||||
GracefulSwitchLoadBalancerAccessor.getChildConfig(priorityChildConfig.childConfig);
|
||||
|
|
@ -873,7 +840,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
@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();
|
||||
|
|
@ -900,9 +867,9 @@ public class ClusterResolverLoadBalancerTest {
|
|||
|
||||
void do_onlyLogicalDnsCluster_resolutionError_backoffAndRefresh() {
|
||||
InOrder inOrder = Mockito.inOrder(helper, backoffPolicyProvider,
|
||||
backoffPolicy1, backoffPolicy2);
|
||||
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();
|
||||
|
|
@ -948,7 +915,7 @@ public class ClusterResolverLoadBalancerTest {
|
|||
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();
|
||||
|
|
@ -984,119 +951,22 @@ public class ClusterResolverLoadBalancerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void edsClustersAndLogicalDnsCluster_receivedEndpoints() {
|
||||
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();
|
||||
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())),
|
||||
"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);
|
||||
}
|
||||
EDS_SERVICE_NAME1, Collections.singletonMap(locality1, localityLbEndpoints));
|
||||
|
||||
@Test
|
||||
public void resolutionErrorAfterChildLbCreated_propagateErrorIfAllClustersEncounterError() {
|
||||
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));
|
||||
assertThat(childBalancers).isEmpty(); // not created until all clusters resolved.
|
||||
|
||||
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
|
||||
|
|
@ -1104,40 +974,19 @@ public class ClusterResolverLoadBalancerTest {
|
|||
|
||||
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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolutionErrorBeforeChildLbCreated_returnErrorPickerIfAllClustersEncounterError() {
|
||||
public void resolutionErrorBeforeChildLbCreated_returnErrorPicker() {
|
||||
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);
|
||||
edsDiscoveryMechanism1, roundRobin, false);
|
||||
deliverLbConfig(config);
|
||||
assertThat(xdsClient.watchers.keySet()).containsExactly(EDS_SERVICE_NAME1);
|
||||
assertThat(childBalancers).isEmpty();
|
||||
|
|
@ -1153,11 +1002,25 @@ public class ClusterResolverLoadBalancerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void handleNameResolutionErrorFromUpstream_beforeChildLbCreated_returnErrorPicker() {
|
||||
public void handleNameResolutionErrorFromUpstream_eds_beforeChildLbCreated_returnErrorPicker() {
|
||||
ClusterResolverConfig config = new ClusterResolverConfig(
|
||||
Arrays.asList(edsDiscoveryMechanism1, logicalDnsDiscoveryMechanism), roundRobin, false);
|
||||
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);
|
||||
|
|
@ -1169,16 +1032,14 @@ public class ClusterResolverLoadBalancerTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void handleNameResolutionErrorFromUpstream_afterChildLbCreated_fallThrough() {
|
||||
public void handleNameResolutionErrorFromUpstream_afterChildLbCreated_eds_fallThrough() {
|
||||
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 endpoint1 = makeAddress("endpoint-addr-1");
|
||||
EquivalentAddressGroup endpoint2 = makeAddress("endpoint-addr-2");
|
||||
LocalityLbEndpoints localityLbEndpoints =
|
||||
LocalityLbEndpoints.create(
|
||||
Collections.singletonList(LbEndpoint.create(endpoint1, 100, true,
|
||||
|
|
@ -1186,12 +1047,34 @@ public class ClusterResolverLoadBalancerTest {
|
|||
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(CLUSTER1 + "[child1]", CLUSTER_DNS + "[child0]");
|
||||
assertAddressesEqual(Arrays.asList(endpoint1, endpoint2), childBalancer.addresses);
|
||||
.containsExactly(CLUSTER_DNS + "[child0]");
|
||||
assertAddressesEqual(Arrays.asList(endpoint2), childBalancer.addresses);
|
||||
|
||||
loadBalancer.handleNameResolutionError(Status.UNAVAILABLE.withDescription("unreachable"));
|
||||
assertThat(childBalancer.upstreamError.getCode()).isEqualTo(Code.UNAVAILABLE);
|
||||
|
|
@ -1205,19 +1088,17 @@ public class ClusterResolverLoadBalancerTest {
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue