diff --git a/xds/src/main/java/io/grpc/xds/LoadBalancerConfigFactory.java b/xds/src/main/java/io/grpc/xds/LoadBalancerConfigFactory.java index 9b1dc722400..81ae3454045 100644 --- a/xds/src/main/java/io/grpc/xds/LoadBalancerConfigFactory.java +++ b/xds/src/main/java/io/grpc/xds/LoadBalancerConfigFactory.java @@ -39,8 +39,8 @@ import io.grpc.LoadBalancerRegistry; import io.grpc.internal.JsonParser; import io.grpc.xds.LoadBalancerConfigFactory.LoadBalancingPolicyConverter.MaxRecursionReachedException; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; import io.grpc.xds.XdsLogger.XdsLogLevel; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import java.io.IOException; import java.util.Map; diff --git a/xds/src/main/java/io/grpc/xds/XdsClient.java b/xds/src/main/java/io/grpc/xds/XdsClient.java index aa222a98d5c..267d5468b62 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClient.java +++ b/xds/src/main/java/io/grpc/xds/XdsClient.java @@ -47,7 +47,7 @@ * protocols (e.g., LDS, RDS, VHDS, CDS and EDS) over a single channel. Watch-based interfaces * are provided for each set of data needed by gRPC. */ -abstract class XdsClient { +public abstract class XdsClient { static boolean isResourceNameValid(String resourceName, String typeUrl) { checkNotNull(resourceName, "resourceName"); @@ -110,8 +110,7 @@ static String percentEncodePath(String input) { return Joiner.on('/').join(encodedSegs); } - interface ResourceUpdate { - } + public interface ResourceUpdate {} /** * Watcher interface for a single requested xDS resource. diff --git a/xds/src/main/java/io/grpc/xds/XdsClientImpl.java b/xds/src/main/java/io/grpc/xds/XdsClientImpl.java index 7389d7ebef1..0e5e7106c17 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClientImpl.java +++ b/xds/src/main/java/io/grpc/xds/XdsClientImpl.java @@ -748,18 +748,6 @@ private void notifyWatcher(ResourceWatcher watcher, T update) { } } - static final class ResourceInvalidException extends Exception { - private static final long serialVersionUID = 0L; - - ResourceInvalidException(String message) { - super(message, null, false, false); - } - - ResourceInvalidException(String message, Throwable cause) { - super(cause != null ? message + ": " + cause.getMessage() : message, cause, false, false); - } - } - abstract static class XdsChannelFactory { static final XdsChannelFactory DEFAULT_XDS_CHANNEL_FACTORY = new XdsChannelFactory() { @Override diff --git a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java index 73b0a975ff4..00285453aab 100644 --- a/xds/src/main/java/io/grpc/xds/XdsClusterResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsClusterResource.java @@ -42,8 +42,8 @@ import io.grpc.xds.EnvoyServerProtoData.OutlierDetection; import io.grpc.xds.EnvoyServerProtoData.UpstreamTlsContext; import io.grpc.xds.XdsClient.ResourceUpdate; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; import io.grpc.xds.XdsClusterResource.CdsUpdate; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import java.util.List; import java.util.Locale; import java.util.Set; @@ -65,7 +65,7 @@ public static XdsClusterResource getInstance() { @Override @Nullable - String extractResourceName(Message unpackedResource) { + protected String extractResourceName(Message unpackedResource) { if (!(unpackedResource instanceof Cluster)) { return null; } @@ -73,29 +73,28 @@ String extractResourceName(Message unpackedResource) { } @Override - String typeName() { + protected String typeName() { return "CDS"; } @Override - String typeUrl() { + protected String typeUrl() { return ADS_TYPE_URL_CDS; } @Override - boolean isFullStateOfTheWorld() { + protected boolean isFullStateOfTheWorld() { return true; } @Override @SuppressWarnings("unchecked") - Class unpackedClassName() { + protected Class unpackedClassName() { return Cluster.class; } @Override - CdsUpdate doParse(Args args, Message unpackedMessage) - throws ResourceInvalidException { + protected CdsUpdate doParse(Args args, Message unpackedMessage) throws ResourceInvalidException { if (!(unpackedMessage instanceof Cluster)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); } diff --git a/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java b/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java index 39caa9a8597..129c664ad25 100644 --- a/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsEndpointResource.java @@ -28,8 +28,8 @@ import io.grpc.xds.Endpoints.DropOverload; import io.grpc.xds.Endpoints.LocalityLbEndpoints; import io.grpc.xds.XdsClient.ResourceUpdate; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; import io.grpc.xds.XdsEndpointResource.EdsUpdate; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.Collections; @@ -54,7 +54,7 @@ public static XdsEndpointResource getInstance() { @Override @Nullable - String extractResourceName(Message unpackedResource) { + protected String extractResourceName(Message unpackedResource) { if (!(unpackedResource instanceof ClusterLoadAssignment)) { return null; } @@ -62,28 +62,27 @@ String extractResourceName(Message unpackedResource) { } @Override - String typeName() { + protected String typeName() { return "EDS"; } @Override - String typeUrl() { + protected String typeUrl() { return ADS_TYPE_URL_EDS; } @Override - boolean isFullStateOfTheWorld() { + protected boolean isFullStateOfTheWorld() { return false; } @Override - Class unpackedClassName() { + protected Class unpackedClassName() { return ClusterLoadAssignment.class; } @Override - EdsUpdate doParse(Args args, Message unpackedMessage) - throws ResourceInvalidException { + protected EdsUpdate doParse(Args args, Message unpackedMessage) throws ResourceInvalidException { if (!(unpackedMessage instanceof ClusterLoadAssignment)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); } diff --git a/xds/src/main/java/io/grpc/xds/XdsListenerResource.java b/xds/src/main/java/io/grpc/xds/XdsListenerResource.java index 62e71a1cbd8..642193c4377 100644 --- a/xds/src/main/java/io/grpc/xds/XdsListenerResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsListenerResource.java @@ -18,8 +18,8 @@ import static com.google.common.base.Preconditions.checkNotNull; import static io.grpc.xds.XdsClient.ResourceUpdate; -import static io.grpc.xds.XdsClientImpl.ResourceInvalidException; import static io.grpc.xds.XdsClusterResource.validateCommonTlsContext; +import static io.grpc.xds.XdsResourceType.ResourceInvalidException; import static io.grpc.xds.XdsRouteConfigureResource.extractVirtualHosts; import com.github.udpa.udpa.type.v1.TypedStruct; @@ -66,7 +66,7 @@ public static XdsListenerResource getInstance() { @Override @Nullable - String extractResourceName(Message unpackedResource) { + protected String extractResourceName(Message unpackedResource) { if (!(unpackedResource instanceof Listener)) { return null; } @@ -74,27 +74,27 @@ String extractResourceName(Message unpackedResource) { } @Override - String typeName() { + protected String typeName() { return "LDS"; } @Override - Class unpackedClassName() { + protected Class unpackedClassName() { return Listener.class; } @Override - String typeUrl() { + protected String typeUrl() { return ADS_TYPE_URL_LDS; } @Override - boolean isFullStateOfTheWorld() { + protected boolean isFullStateOfTheWorld() { return true; } @Override - LdsUpdate doParse(Args args, Message unpackedMessage) + protected LdsUpdate doParse(Args args, Message unpackedMessage) throws ResourceInvalidException { if (!(unpackedMessage instanceof Listener)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); diff --git a/xds/src/main/java/io/grpc/xds/XdsResourceType.java b/xds/src/main/java/io/grpc/xds/XdsResourceType.java index 1bec72d492c..ce2bb7301a7 100644 --- a/xds/src/main/java/io/grpc/xds/XdsResourceType.java +++ b/xds/src/main/java/io/grpc/xds/XdsResourceType.java @@ -21,7 +21,6 @@ import static io.grpc.xds.XdsClient.ResourceUpdate; import static io.grpc.xds.XdsClient.canonifyResourceName; import static io.grpc.xds.XdsClient.isResourceNameValid; -import static io.grpc.xds.XdsClientImpl.ResourceInvalidException; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; @@ -29,7 +28,10 @@ import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; import io.envoyproxy.envoy.service.discovery.v3.Resource; +import io.grpc.ExperimentalApi; import io.grpc.LoadBalancerRegistry; +import io.grpc.xds.Bootstrapper.ServerInfo; +import io.grpc.xds.XdsClient.ResourceUpdate; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -38,7 +40,8 @@ import java.util.Set; import javax.annotation.Nullable; -abstract class XdsResourceType { +@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10847") +public abstract class XdsResourceType { static final String TYPE_URL_RESOURCE = "type.googleapis.com/envoy.service.discovery.v3.Resource"; static final String TRANSPORT_SOCKET_NAME_TLS = "envoy.transport_sockets.tls"; @@ -68,22 +71,22 @@ abstract class XdsResourceType { "type.googleapis.com/xds.type.v3.TypedStruct"; @Nullable - abstract String extractResourceName(Message unpackedResource); + protected abstract String extractResourceName(Message unpackedResource); - abstract Class unpackedClassName(); + protected abstract Class unpackedClassName(); - abstract String typeName(); + protected abstract String typeName(); - abstract String typeUrl(); + protected abstract String typeUrl(); // Do not confuse with the SotW approach: it is the mechanism in which the client must specify all // resource names it is interested in with each request. Different resource types may behave // differently in this approach. For LDS and CDS resources, the server must return all resources // that the client has subscribed to in each request. For RDS and EDS, the server may only return // the resources that need an update. - abstract boolean isFullStateOfTheWorld(); + protected abstract boolean isFullStateOfTheWorld(); - static class Args { + public static class Args { final ServerInfo serverInfo; final String versionInfo; final String nonce; @@ -114,6 +117,18 @@ public Args(ServerInfo serverInfo, String versionInfo, String nonce, } } + public static final class ResourceInvalidException extends Exception { + private static final long serialVersionUID = 0L; + + public ResourceInvalidException(String message) { + super(message, null, false, false); + } + + public ResourceInvalidException(String message, Throwable cause) { + super(cause != null ? message + ": " + cause.getMessage() : message, cause, false, false); + } + } + ValidatedResourceUpdate parse(Args args, List resources) { Map> parsedResources = new HashMap<>(resources.size()); Set unpackedResources = new HashSet<>(resources.size()); @@ -147,7 +162,7 @@ ValidatedResourceUpdate parse(Args args, List resources) { T resourceUpdate; try { resourceUpdate = doParse(args, unpackedMessage); - } catch (XdsClientImpl.ResourceInvalidException e) { + } catch (ResourceInvalidException e) { errors.add(String.format("%s response %s '%s' validation error: %s", typeName(), unpackedClassName().getSimpleName(), cname, e.getMessage())); invalidResources.add(cname); @@ -162,7 +177,7 @@ ValidatedResourceUpdate parse(Args args, List resources) { } - abstract T doParse(Args args, Message unpackedMessage) throws ResourceInvalidException; + protected abstract T doParse(Args args, Message unpackedMessage) throws ResourceInvalidException; /** * Helper method to unpack serialized {@link com.google.protobuf.Any} message, while replacing diff --git a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java index 47f6f6beeea..7adac68df1e 100644 --- a/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java +++ b/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java @@ -49,7 +49,7 @@ import io.grpc.xds.VirtualHost.Route.RouteMatch; import io.grpc.xds.VirtualHost.Route.RouteMatch.PathMatcher; import io.grpc.xds.XdsClient.ResourceUpdate; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import io.grpc.xds.XdsRouteConfigureResource.RdsUpdate; import io.grpc.xds.internal.MatcherParser; import io.grpc.xds.internal.Matchers; @@ -85,7 +85,7 @@ public static XdsRouteConfigureResource getInstance() { @Override @Nullable - String extractResourceName(Message unpackedResource) { + protected String extractResourceName(Message unpackedResource) { if (!(unpackedResource instanceof RouteConfiguration)) { return null; } @@ -93,27 +93,27 @@ String extractResourceName(Message unpackedResource) { } @Override - String typeName() { + protected String typeName() { return "RDS"; } @Override - String typeUrl() { + protected String typeUrl() { return ADS_TYPE_URL_RDS; } @Override - boolean isFullStateOfTheWorld() { + protected boolean isFullStateOfTheWorld() { return false; } @Override - Class unpackedClassName() { + protected Class unpackedClassName() { return RouteConfiguration.class; } @Override - RdsUpdate doParse(XdsResourceType.Args args, Message unpackedMessage) + protected RdsUpdate doParse(XdsResourceType.Args args, Message unpackedMessage) throws ResourceInvalidException { if (!(unpackedMessage instanceof RouteConfiguration)) { throw new ResourceInvalidException("Invalid message type: " + unpackedMessage.getClass()); diff --git a/xds/src/test/java/io/grpc/xds/LoadBalancerConfigFactoryTest.java b/xds/src/test/java/io/grpc/xds/LoadBalancerConfigFactoryTest.java index fe500105bc6..00e1ab686a6 100644 --- a/xds/src/test/java/io/grpc/xds/LoadBalancerConfigFactoryTest.java +++ b/xds/src/test/java/io/grpc/xds/LoadBalancerConfigFactoryTest.java @@ -52,7 +52,7 @@ import io.grpc.internal.JsonUtil; import io.grpc.internal.ServiceConfigUtil; import io.grpc.internal.ServiceConfigUtil.LbConfig; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import java.util.List; import org.junit.After; import org.junit.Test; diff --git a/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java b/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java index b73240490c5..66fbb7d1ed5 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientImplDataTest.java @@ -134,8 +134,8 @@ import io.grpc.xds.VirtualHost.Route.RouteMatch; import io.grpc.xds.VirtualHost.Route.RouteMatch.PathMatcher; import io.grpc.xds.WeightedRoundRobinLoadBalancer.WeightedRoundRobinLoadBalancerConfig; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; import io.grpc.xds.XdsClusterResource.CdsUpdate; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import io.grpc.xds.XdsResourceType.StructOrError; import io.grpc.xds.internal.Matchers; import io.grpc.xds.internal.Matchers.FractionMatcher; diff --git a/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java b/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java index 4c3e05d8f1b..06f4dd9a625 100644 --- a/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java +++ b/xds/src/test/java/io/grpc/xds/XdsClientImplTestBase.java @@ -91,12 +91,12 @@ import io.grpc.xds.XdsClient.ResourceMetadata.UpdateFailureState; import io.grpc.xds.XdsClient.ResourceUpdate; import io.grpc.xds.XdsClient.ResourceWatcher; -import io.grpc.xds.XdsClientImpl.ResourceInvalidException; import io.grpc.xds.XdsClientImpl.XdsChannelFactory; import io.grpc.xds.XdsClusterResource.CdsUpdate; import io.grpc.xds.XdsClusterResource.CdsUpdate.ClusterType; import io.grpc.xds.XdsEndpointResource.EdsUpdate; import io.grpc.xds.XdsListenerResource.LdsUpdate; +import io.grpc.xds.XdsResourceType.ResourceInvalidException; import io.grpc.xds.XdsRouteConfigureResource.RdsUpdate; import io.grpc.xds.internal.security.CommonTlsContextTestsUtil; import java.io.IOException; @@ -2242,7 +2242,7 @@ public void cdsResponseErrorHandling_badUpstreamTlsContext() { // The response NACKed with errors indicating indices of the failed resources. String errorMsg = "CDS response Cluster 'cluster.googleapis.com' validation error: " + "Cluster cluster.googleapis.com: malformed UpstreamTlsContext: " - + "io.grpc.xds.XdsClientImpl$ResourceInvalidException: " + + "io.grpc.xds.XdsResourceType$ResourceInvalidException: " + "ca_certificate_provider_instance is required in upstream-tls-context"; call.verifyRequestNack(CDS, CDS_RESOURCE, "", "0000", NODE, ImmutableList.of(errorMsg)); verify(cdsResourceWatcher).onError(errorCaptor.capture()); @@ -2349,7 +2349,7 @@ public void cdsResponseWithInvalidOutlierDetectionNacks() { String errorMsg = "CDS response Cluster 'cluster.googleapis.com' validation error: " + "Cluster cluster.googleapis.com: malformed outlier_detection: " - + "io.grpc.xds.XdsClientImpl$ResourceInvalidException: outlier_detection " + + "io.grpc.xds.XdsResourceType$ResourceInvalidException: outlier_detection " + "max_ejection_percent is > 100"; call.verifyRequestNack(CDS, CDS_RESOURCE, "", "0000", NODE, ImmutableList.of(errorMsg)); verify(cdsResourceWatcher).onError(errorCaptor.capture());