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 io.grpc.Internal; 23 import io.grpc.LoadBalancer; 24 import io.grpc.LoadBalancer.Helper; 25 import io.grpc.LoadBalancerProvider; 26 import io.grpc.NameResolver.ConfigOrError; 27 import io.grpc.Status; 28 import io.grpc.internal.ServiceConfigUtil.PolicySelection; 29 import io.grpc.xds.Bootstrapper.ServerInfo; 30 import io.grpc.xds.EnvoyServerProtoData.OutlierDetection; 31 import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; 32 import java.util.List; 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 { 44 45 @Override isAvailable()46 public boolean isAvailable() { 47 return true; 48 } 49 50 @Override getPriority()51 public int getPriority() { 52 return 5; 53 } 54 55 @Override getPolicyName()56 public String getPolicyName() { 57 return XdsLbPolicies.CLUSTER_RESOLVER_POLICY_NAME; 58 } 59 60 @Override parseLoadBalancingPolicyConfig(Map<String, ?> rawLoadBalancingPolicyConfig)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 newLoadBalancer(Helper helper)67 public LoadBalancer newLoadBalancer(Helper helper) { 68 return new ClusterResolverLoadBalancer(helper); 69 } 70 71 static final class ClusterResolverConfig { 72 // Ordered list of clusters to be resolved. 73 final List<DiscoveryMechanism> discoveryMechanisms; 74 // Endpoint-level load balancing policy with config 75 // (round_robin, least_request_experimental or ring_hash_experimental). 76 final PolicySelection lbPolicy; 77 ClusterResolverConfig(List<DiscoveryMechanism> discoveryMechanisms, PolicySelection lbPolicy)78 ClusterResolverConfig(List<DiscoveryMechanism> discoveryMechanisms, PolicySelection lbPolicy) { 79 this.discoveryMechanisms = checkNotNull(discoveryMechanisms, "discoveryMechanisms"); 80 this.lbPolicy = checkNotNull(lbPolicy, "lbPolicy"); 81 } 82 83 @Override hashCode()84 public int hashCode() { 85 return Objects.hash(discoveryMechanisms, lbPolicy); 86 } 87 88 @Override equals(Object o)89 public boolean equals(Object o) { 90 if (this == o) { 91 return true; 92 } 93 if (o == null || getClass() != o.getClass()) { 94 return false; 95 } 96 ClusterResolverConfig that = (ClusterResolverConfig) o; 97 return discoveryMechanisms.equals(that.discoveryMechanisms) 98 && lbPolicy.equals(that.lbPolicy); 99 } 100 101 @Override toString()102 public String toString() { 103 return MoreObjects.toStringHelper(this) 104 .add("discoveryMechanisms", discoveryMechanisms) 105 .add("lbPolicy", lbPolicy) 106 .toString(); 107 } 108 109 // Describes the mechanism for a specific cluster. 110 static final class DiscoveryMechanism { 111 // Name of the cluster to resolve. 112 final String cluster; 113 // Type of the cluster. 114 final Type type; 115 // Load reporting server info. Null if not enabled. 116 @Nullable 117 final ServerInfo lrsServerInfo; 118 // Cluster-level max concurrent request threshold. Null if not specified. 119 @Nullable 120 final Long maxConcurrentRequests; 121 // TLS context for connections to endpoints in the cluster. 122 @Nullable 123 final UpstreamTlsContext tlsContext; 124 // Resource name for resolving endpoints via EDS. Only valid for EDS clusters. 125 @Nullable 126 final String edsServiceName; 127 // Hostname for resolving endpoints via DNS. Only valid for LOGICAL_DNS clusters. 128 @Nullable 129 final String dnsHostName; 130 @Nullable 131 final OutlierDetection outlierDetection; 132 133 enum Type { 134 EDS, 135 LOGICAL_DNS, 136 } 137 DiscoveryMechanism(String cluster, Type type, @Nullable String edsServiceName, @Nullable String dnsHostName, @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext, @Nullable OutlierDetection outlierDetection)138 private DiscoveryMechanism(String cluster, Type type, @Nullable String edsServiceName, 139 @Nullable String dnsHostName, @Nullable ServerInfo lrsServerInfo, 140 @Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext, 141 @Nullable OutlierDetection outlierDetection) { 142 this.cluster = checkNotNull(cluster, "cluster"); 143 this.type = checkNotNull(type, "type"); 144 this.edsServiceName = edsServiceName; 145 this.dnsHostName = dnsHostName; 146 this.lrsServerInfo = lrsServerInfo; 147 this.maxConcurrentRequests = maxConcurrentRequests; 148 this.tlsContext = tlsContext; 149 this.outlierDetection = outlierDetection; 150 } 151 forEds(String cluster, @Nullable String edsServiceName, @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext, OutlierDetection outlierDetection)152 static DiscoveryMechanism forEds(String cluster, @Nullable String edsServiceName, 153 @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests, 154 @Nullable UpstreamTlsContext tlsContext, 155 OutlierDetection outlierDetection) { 156 return new DiscoveryMechanism(cluster, Type.EDS, edsServiceName, null, lrsServerInfo, 157 maxConcurrentRequests, tlsContext, outlierDetection); 158 } 159 forLogicalDns(String cluster, String dnsHostName, @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests, @Nullable UpstreamTlsContext tlsContext)160 static DiscoveryMechanism forLogicalDns(String cluster, String dnsHostName, 161 @Nullable ServerInfo lrsServerInfo, @Nullable Long maxConcurrentRequests, 162 @Nullable UpstreamTlsContext tlsContext) { 163 return new DiscoveryMechanism(cluster, Type.LOGICAL_DNS, null, dnsHostName, 164 lrsServerInfo, maxConcurrentRequests, tlsContext, null); 165 } 166 167 @Override hashCode()168 public int hashCode() { 169 return Objects.hash(cluster, type, lrsServerInfo, maxConcurrentRequests, tlsContext, 170 edsServiceName, dnsHostName); 171 } 172 173 @Override equals(Object o)174 public boolean equals(Object o) { 175 if (this == o) { 176 return true; 177 } 178 if (o == null || getClass() != o.getClass()) { 179 return false; 180 } 181 DiscoveryMechanism that = (DiscoveryMechanism) o; 182 return cluster.equals(that.cluster) 183 && type == that.type 184 && Objects.equals(edsServiceName, that.edsServiceName) 185 && Objects.equals(dnsHostName, that.dnsHostName) 186 && Objects.equals(lrsServerInfo, that.lrsServerInfo) 187 && Objects.equals(maxConcurrentRequests, that.maxConcurrentRequests) 188 && Objects.equals(tlsContext, that.tlsContext); 189 } 190 191 @Override toString()192 public String toString() { 193 MoreObjects.ToStringHelper toStringHelper = 194 MoreObjects.toStringHelper(this) 195 .add("cluster", cluster) 196 .add("type", type) 197 .add("edsServiceName", edsServiceName) 198 .add("dnsHostName", dnsHostName) 199 .add("lrsServerInfo", lrsServerInfo) 200 // Exclude tlsContext as its string representation is cumbersome. 201 .add("maxConcurrentRequests", maxConcurrentRequests); 202 return toStringHelper.toString(); 203 } 204 } 205 } 206 } 207