• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19928

29 Jul 2025 12:36PM UTC coverage: 88.586% (-0.01%) from 88.599%
#19928

push

github

web-flow
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.

34654 of 39119 relevant lines covered (88.59%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.45
/../xds/src/main/java/io/grpc/xds/ClusterResolverLoadBalancerProvider.java
1
/*
2
 * Copyright 2020 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.base.MoreObjects;
22
import com.google.common.collect.ImmutableMap;
23
import com.google.protobuf.Struct;
24
import io.grpc.Internal;
25
import io.grpc.LoadBalancer;
26
import io.grpc.LoadBalancer.Helper;
27
import io.grpc.LoadBalancerProvider;
28
import io.grpc.NameResolver.ConfigOrError;
29
import io.grpc.Status;
30
import io.grpc.xds.EnvoyServerProtoData.OutlierDetection;
31
import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext;
32
import io.grpc.xds.client.Bootstrapper.ServerInfo;
33
import java.util.Map;
34
import java.util.Objects;
35
import javax.annotation.Nullable;
36

37
/**
38
 * The provider for the cluster_resolver load balancing policy. This class should not be directly
39
 * referenced in code.  The policy should be accessed through
40
 * {@link io.grpc.LoadBalancerRegistry#getProvider} with the name "cluster_resolver_experimental".
41
 */
42
@Internal
43
public final class ClusterResolverLoadBalancerProvider extends LoadBalancerProvider {
1✔
44

45
  @Override
46
  public boolean isAvailable() {
47
    return true;
1✔
48
  }
49

50
  @Override
51
  public int getPriority() {
52
    return 5;
1✔
53
  }
54

55
  @Override
56
  public String getPolicyName() {
57
    return XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME;
1✔
58
  }
59

60
  @Override
61
  public ConfigOrError parseLoadBalancingPolicyConfig(Map<String, ?> rawLoadBalancingPolicyConfig) {
62
    return ConfigOrError.fromError(
×
63
        Status.INTERNAL.withDescription(getPolicyName() + " cannot be used from service config"));
×
64
  }
65

66
  @Override
67
  public LoadBalancer newLoadBalancer(Helper helper) {
68
    return new ClusterResolverLoadBalancer(helper);
1✔
69
  }
70

71
  static final class ClusterResolverConfig {
72
    // Cluster to be resolved.
73
    final DiscoveryMechanism discoveryMechanism;
74
    // GracefulSwitch configuration
75
    final Object lbConfig;
76
    private final boolean isHttp11ProxyAvailable;
77

78
    ClusterResolverConfig(DiscoveryMechanism discoveryMechanism, Object lbConfig,
79
        boolean isHttp11ProxyAvailable) {
1✔
80
      this.discoveryMechanism = checkNotNull(discoveryMechanism, "discoveryMechanism");
1✔
81
      this.lbConfig = checkNotNull(lbConfig, "lbConfig");
1✔
82
      this.isHttp11ProxyAvailable = isHttp11ProxyAvailable;
1✔
83
    }
1✔
84

85
    boolean isHttp11ProxyAvailable() {
86
      return isHttp11ProxyAvailable;
1✔
87
    }
88

89
    @Override
90
    public int hashCode() {
91
      return Objects.hash(discoveryMechanism, lbConfig, isHttp11ProxyAvailable);
1✔
92
    }
93

94
    @Override
95
    public boolean equals(Object o) {
96
      if (this == o) {
1✔
97
        return true;
1✔
98
      }
99
      if (o == null || getClass() != o.getClass()) {
1✔
100
        return false;
1✔
101
      }
102
      ClusterResolverConfig that = (ClusterResolverConfig) o;
1✔
103
      return discoveryMechanism.equals(that.discoveryMechanism)
1✔
104
          && lbConfig.equals(that.lbConfig)
1✔
105
          && isHttp11ProxyAvailable == that.isHttp11ProxyAvailable;
106
    }
107

108
    @Override
109
    public String toString() {
110
      return MoreObjects.toStringHelper(this)
1✔
111
          .add("discoveryMechanism", discoveryMechanism)
1✔
112
          .add("lbConfig", lbConfig)
1✔
113
          .add("isHttp11ProxyAvailable", isHttp11ProxyAvailable)
1✔
114
          .toString();
1✔
115
    }
116

117
    // Describes the mechanism for a specific cluster.
118
    static final class DiscoveryMechanism {
119
      // Name of the cluster to resolve.
120
      final String cluster;
121
      // Type of the cluster.
122
      final Type type;
123
      // Load reporting server info. Null if not enabled.
124
      @Nullable
125
      final ServerInfo lrsServerInfo;
126
      // Cluster-level max concurrent request threshold. Null if not specified.
127
      @Nullable
128
      final Long maxConcurrentRequests;
129
      // TLS context for connections to endpoints in the cluster.
130
      @Nullable
131
      final UpstreamTlsContext tlsContext;
132
      // Resource name for resolving endpoints via EDS. Only valid for EDS clusters.
133
      @Nullable
134
      final String edsServiceName;
135
      // Hostname for resolving endpoints via DNS. Only valid for LOGICAL_DNS clusters.
136
      @Nullable
137
      final String dnsHostName;
138
      @Nullable
139
      final OutlierDetection outlierDetection;
140
      final Map<String, Struct> filterMetadata;
141

142
      enum Type {
1✔
143
        EDS,
1✔
144
        LOGICAL_DNS,
1✔
145
      }
146

147
      private DiscoveryMechanism(String cluster, Type type, @Nullable String edsServiceName,
148
          @Nullable String dnsHostName, @Nullable ServerInfo lrsServerInfo,
149
          @Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext,
150
          Map<String, Struct> filterMetadata, @Nullable OutlierDetection outlierDetection) {
1✔
151
        this.cluster = checkNotNull(cluster, "cluster");
1✔
152
        this.type = checkNotNull(type, "type");
1✔
153
        this.edsServiceName = edsServiceName;
1✔
154
        this.dnsHostName = dnsHostName;
1✔
155
        this.lrsServerInfo = lrsServerInfo;
1✔
156
        this.maxConcurrentRequests = maxConcurrentRequests;
1✔
157
        this.tlsContext = tlsContext;
1✔
158
        this.filterMetadata = ImmutableMap.copyOf(checkNotNull(filterMetadata, "filterMetadata"));
1✔
159
        this.outlierDetection = outlierDetection;
1✔
160
      }
1✔
161

162
      static DiscoveryMechanism forEds(String cluster, @Nullable String edsServiceName,
163
          @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests,
164
          @Nullable UpstreamTlsContext tlsContext, Map<String, Struct> filterMetadata,
165
          OutlierDetection outlierDetection) {
166
        return new DiscoveryMechanism(cluster, Type.EDS, edsServiceName, null, lrsServerInfo,
1✔
167
            maxConcurrentRequests, tlsContext, filterMetadata, outlierDetection);
168
      }
169

170
      static DiscoveryMechanism forLogicalDns(String cluster, String dnsHostName,
171
          @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests,
172
          @Nullable UpstreamTlsContext tlsContext, Map<String, Struct> filterMetadata) {
173
        return new DiscoveryMechanism(cluster, Type.LOGICAL_DNS, null, dnsHostName,
1✔
174
            lrsServerInfo, maxConcurrentRequests, tlsContext, filterMetadata, null);
175
      }
176

177
      @Override
178
      public int hashCode() {
179
        return Objects.hash(cluster, type, lrsServerInfo, maxConcurrentRequests, tlsContext,
1✔
180
            edsServiceName, dnsHostName, filterMetadata, outlierDetection);
181
      }
182

183
      @Override
184
      public boolean equals(Object o) {
185
        if (this == o) {
1✔
186
          return true;
1✔
187
        }
188
        if (o == null || getClass() != o.getClass()) {
1✔
189
          return false;
×
190
        }
191
        DiscoveryMechanism that = (DiscoveryMechanism) o;
1✔
192
        return cluster.equals(that.cluster)
1✔
193
            && type == that.type
194
            && Objects.equals(edsServiceName, that.edsServiceName)
1✔
195
            && Objects.equals(dnsHostName, that.dnsHostName)
1✔
196
            && Objects.equals(lrsServerInfo, that.lrsServerInfo)
1✔
197
            && Objects.equals(maxConcurrentRequests, that.maxConcurrentRequests)
1✔
198
            && Objects.equals(tlsContext, that.tlsContext)
1✔
199
            && Objects.equals(filterMetadata, that.filterMetadata)
1✔
200
            && Objects.equals(outlierDetection, that.outlierDetection);
1✔
201
      }
202

203
      @Override
204
      public String toString() {
205
        MoreObjects.ToStringHelper toStringHelper =
1✔
206
            MoreObjects.toStringHelper(this)
1✔
207
                .add("cluster", cluster)
1✔
208
                .add("type", type)
1✔
209
                .add("edsServiceName", edsServiceName)
1✔
210
                .add("dnsHostName", dnsHostName)
1✔
211
                .add("lrsServerInfo", lrsServerInfo)
1✔
212
                // Exclude tlsContext as its string representation is cumbersome.
213
                .add("maxConcurrentRequests", maxConcurrentRequests)
1✔
214
                .add("filterMetadata", filterMetadata)
1✔
215
                // Exclude outlierDetection as its string representation is long.
216
                ;
217
        return toStringHelper.toString();
1✔
218
      }
219
    }
220
  }
221
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc