Skip to content

Commit

Permalink
xds: parse resources in ADS response to envoy-api v3 objects
Browse files Browse the repository at this point in the history
Continuation of grpc#7169 to parse all resources in ADS response to v3 objects. In this PR we still only send v2 requests to xDS server (No v3 bootstrap or env flag support).
  • Loading branch information
dapengzhang0 authored and dfawley committed Jan 15, 2021
1 parent 804be8d commit 6e7bfd4
Show file tree
Hide file tree
Showing 18 changed files with 1,821 additions and 364 deletions.
113 changes: 85 additions & 28 deletions xds/src/main/java/io/grpc/xds/EnvoyProtoData.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
import com.google.common.collect.ImmutableList;
import com.google.re2j.Pattern;
import com.google.re2j.PatternSyntaxException;
import io.envoyproxy.envoy.type.FractionalPercent;
import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType;
import io.envoyproxy.envoy.type.v3.FractionalPercent;
import io.envoyproxy.envoy.type.v3.FractionalPercent.DenominatorType;
import io.grpc.EquivalentAddressGroup;
import io.grpc.xds.RouteMatch.FractionMatcher;
import io.grpc.xds.RouteMatch.HeaderMatcher;
Expand Down Expand Up @@ -148,7 +148,15 @@ static final class Locality {
this.subZone = subZone;
}

static Locality fromEnvoyProtoLocality(io.envoyproxy.envoy.api.v2.core.Locality locality) {
static Locality fromEnvoyProtoLocality(io.envoyproxy.envoy.config.core.v3.Locality locality) {
return new Locality(
/* region = */ locality.getRegion(),
/* zone = */ locality.getZone(),
/* subZone = */ locality.getSubZone());
}

@VisibleForTesting
static Locality fromEnvoyProtoLocalityV2(io.envoyproxy.envoy.api.v2.core.Locality locality) {
return new Locality(
/* region = */ locality.getRegion(),
/* zone = */ locality.getZone(),
Expand Down Expand Up @@ -222,10 +230,25 @@ static final class LocalityLbEndpoints {
}

static LocalityLbEndpoints fromEnvoyProtoLocalityLbEndpoints(
io.envoyproxy.envoy.config.endpoint.v3.LocalityLbEndpoints proto) {
List<LbEndpoint> endpoints = new ArrayList<>(proto.getLbEndpointsCount());
for (io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint endpoint :
proto.getLbEndpointsList()) {
endpoints.add(LbEndpoint.fromEnvoyProtoLbEndpoint(endpoint));
}
return
new LocalityLbEndpoints(
endpoints,
proto.getLoadBalancingWeight().getValue(),
proto.getPriority());
}

@VisibleForTesting
static LocalityLbEndpoints fromEnvoyProtoLocalityLbEndpointsV2(
io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints proto) {
List<LbEndpoint> endpoints = new ArrayList<>(proto.getLbEndpointsCount());
for (io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint endpoint : proto.getLbEndpointsList()) {
endpoints.add(LbEndpoint.fromEnvoyProtoLbEndpoint(endpoint));
endpoints.add(LbEndpoint.fromEnvoyProtoLbEndpointV2(endpoint));
}
return
new LocalityLbEndpoints(
Expand Down Expand Up @@ -299,18 +322,30 @@ static final class LbEndpoint {
}

static LbEndpoint fromEnvoyProtoLbEndpoint(
io.envoyproxy.envoy.config.endpoint.v3.LbEndpoint proto) {
io.envoyproxy.envoy.config.core.v3.SocketAddress socketAddress =
proto.getEndpoint().getAddress().getSocketAddress();
InetSocketAddress addr =
new InetSocketAddress(socketAddress.getAddress(), socketAddress.getPortValue());
return new LbEndpoint(
new EquivalentAddressGroup(ImmutableList.<java.net.SocketAddress>of(addr)),
proto.getLoadBalancingWeight().getValue(),
proto.getHealthStatus() == io.envoyproxy.envoy.config.core.v3.HealthStatus.HEALTHY
|| proto.getHealthStatus()
== io.envoyproxy.envoy.config.core.v3.HealthStatus.UNKNOWN);
}

private static LbEndpoint fromEnvoyProtoLbEndpointV2(
io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint proto) {
io.envoyproxy.envoy.api.v2.core.SocketAddress socketAddress =
proto.getEndpoint().getAddress().getSocketAddress();
InetSocketAddress addr =
new InetSocketAddress(socketAddress.getAddress(), socketAddress.getPortValue());
return
new LbEndpoint(
new EquivalentAddressGroup(ImmutableList.<java.net.SocketAddress>of(addr)),
proto.getLoadBalancingWeight().getValue(),
proto.getHealthStatus() == io.envoyproxy.envoy.api.v2.core.HealthStatus.HEALTHY
|| proto.getHealthStatus() == io.envoyproxy.envoy.api.v2.core.HealthStatus.UNKNOWN
);
return new LbEndpoint(
new EquivalentAddressGroup(ImmutableList.<java.net.SocketAddress>of(addr)),
proto.getLoadBalancingWeight().getValue(),
proto.getHealthStatus() == io.envoyproxy.envoy.api.v2.core.HealthStatus.HEALTHY
|| proto.getHealthStatus() == io.envoyproxy.envoy.api.v2.core.HealthStatus.UNKNOWN);
}

EquivalentAddressGroup getAddress() {
Expand Down Expand Up @@ -370,7 +405,7 @@ static final class DropOverload {
}

static DropOverload fromEnvoyProtoDropOverload(
io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload proto) {
io.envoyproxy.envoy.config.endpoint.v3.ClusterLoadAssignment.Policy.DropOverload proto) {
FractionalPercent percent = proto.getDropPercentage();
int numerator = percent.getNumerator();
DenominatorType type = percent.getDenominator();
Expand All @@ -379,7 +414,33 @@ static DropOverload fromEnvoyProtoDropOverload(
numerator *= 100;
break;
case HUNDRED:
numerator *= 100_00;
numerator *= 10_000;
break;
case MILLION:
break;
default:
throw new IllegalArgumentException("Unknown denominator type of " + percent);
}

if (numerator > 1_000_000) {
numerator = 1_000_000;
}

return new DropOverload(proto.getCategory(), numerator);
}

@VisibleForTesting
static DropOverload fromEnvoyProtoDropOverloadV2(
io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload proto) {
io.envoyproxy.envoy.type.FractionalPercent percent = proto.getDropPercentage();
int numerator = percent.getNumerator();
io.envoyproxy.envoy.type.FractionalPercent.DenominatorType type = percent.getDenominator();
switch (type) {
case TEN_THOUSAND:
numerator *= 100;
break;
case HUNDRED:
numerator *= 10_000;
break;
case MILLION:
break;
Expand Down Expand Up @@ -484,7 +545,8 @@ public String toString() {
}

@Nullable
static StructOrError<Route> fromEnvoyProtoRoute(io.envoyproxy.envoy.api.v2.route.Route proto) {
static StructOrError<Route> fromEnvoyProtoRoute(
io.envoyproxy.envoy.config.route.v3.Route proto) {
StructOrError<RouteMatch> routeMatch = convertEnvoyProtoRouteMatch(proto.getMatch());
if (routeMatch == null) {
return null;
Expand Down Expand Up @@ -523,7 +585,7 @@ static StructOrError<Route> fromEnvoyProtoRoute(io.envoyproxy.envoy.api.v2.route
@SuppressWarnings("deprecation")
@Nullable
static StructOrError<RouteMatch> convertEnvoyProtoRouteMatch(
io.envoyproxy.envoy.api.v2.route.RouteMatch proto) {
io.envoyproxy.envoy.config.route.v3.RouteMatch proto) {
if (proto.getQueryParametersCount() != 0) {
return null;
}
Expand All @@ -547,7 +609,7 @@ static StructOrError<RouteMatch> convertEnvoyProtoRouteMatch(
}

List<HeaderMatcher> headerMatchers = new ArrayList<>();
for (io.envoyproxy.envoy.api.v2.route.HeaderMatcher hmProto : proto.getHeadersList()) {
for (io.envoyproxy.envoy.config.route.v3.HeaderMatcher hmProto : proto.getHeadersList()) {
StructOrError<HeaderMatcher> headerMatcher = convertEnvoyProtoHeaderMatcher(hmProto);
if (headerMatcher.getErrorDetail() != null) {
return StructOrError.fromError(headerMatcher.getErrorDetail());
Expand All @@ -562,7 +624,7 @@ static StructOrError<RouteMatch> convertEnvoyProtoRouteMatch(

@SuppressWarnings("deprecation")
private static StructOrError<PathMatcher> convertEnvoyProtoPathMatcher(
io.envoyproxy.envoy.api.v2.route.RouteMatch proto) {
io.envoyproxy.envoy.config.route.v3.RouteMatch proto) {
String path = null;
String prefix = null;
Pattern safeRegEx = null;
Expand All @@ -573,8 +635,6 @@ private static StructOrError<PathMatcher> convertEnvoyProtoPathMatcher(
case PATH:
path = proto.getPath();
break;
case REGEX:
return StructOrError.fromError("Unsupported path match type: regex");
case SAFE_REGEX:
String rawPattern = proto.getSafeRegex().getRegex();
try {
Expand All @@ -591,7 +651,7 @@ private static StructOrError<PathMatcher> convertEnvoyProtoPathMatcher(
}

private static StructOrError<FractionMatcher> convertEnvoyProtoFraction(
io.envoyproxy.envoy.type.FractionalPercent proto) {
io.envoyproxy.envoy.type.v3.FractionalPercent proto) {
int numerator = proto.getNumerator();
int denominator = 0;
switch (proto.getDenominator()) {
Expand All @@ -615,7 +675,7 @@ private static StructOrError<FractionMatcher> convertEnvoyProtoFraction(
@VisibleForTesting
@SuppressWarnings("deprecation")
static StructOrError<HeaderMatcher> convertEnvoyProtoHeaderMatcher(
io.envoyproxy.envoy.api.v2.route.HeaderMatcher proto) {
io.envoyproxy.envoy.config.route.v3.HeaderMatcher proto) {
String exactMatch = null;
Pattern safeRegExMatch = null;
HeaderMatcher.Range rangeMatch = null;
Expand All @@ -627,9 +687,6 @@ static StructOrError<HeaderMatcher> convertEnvoyProtoHeaderMatcher(
case EXACT_MATCH:
exactMatch = proto.getExactMatch();
break;
case REGEX_MATCH:
return StructOrError.fromError(
"HeaderMatcher [" + proto.getName() + "] has unsupported match type: regex");
case SAFE_REGEX_MATCH:
String rawPattern = proto.getSafeRegexMatch().getRegex();
try {
Expand Down Expand Up @@ -722,7 +779,7 @@ public String toString() {
@Nullable
@VisibleForTesting
static StructOrError<RouteAction> fromEnvoyProtoRouteAction(
io.envoyproxy.envoy.api.v2.route.RouteAction proto) {
io.envoyproxy.envoy.config.route.v3.RouteAction proto) {
String cluster = null;
List<ClusterWeight> weightedClusters = null;
switch (proto.getClusterSpecifierCase()) {
Expand All @@ -732,10 +789,10 @@ static StructOrError<RouteAction> fromEnvoyProtoRouteAction(
case CLUSTER_HEADER:
return null;
case WEIGHTED_CLUSTERS:
List<io.envoyproxy.envoy.api.v2.route.WeightedCluster.ClusterWeight> clusterWeights
List<io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight> clusterWeights
= proto.getWeightedClusters().getClustersList();
weightedClusters = new ArrayList<>();
for (io.envoyproxy.envoy.api.v2.route.WeightedCluster.ClusterWeight clusterWeight
for (io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight clusterWeight
: clusterWeights) {
weightedClusters.add(ClusterWeight.fromEnvoyProtoClusterWeight(clusterWeight));
}
Expand Down Expand Up @@ -799,7 +856,7 @@ public String toString() {

@VisibleForTesting
static ClusterWeight fromEnvoyProtoClusterWeight(
io.envoyproxy.envoy.api.v2.route.WeightedCluster.ClusterWeight proto) {
io.envoyproxy.envoy.config.route.v3.WeightedCluster.ClusterWeight proto) {
return new ClusterWeight(proto.getName(), proto.getWeight().getValue());
}
}
Expand Down

0 comments on commit 6e7bfd4

Please sign in to comment.