From e99672e03d65a1b773506f2902f1e030a804a885 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 11 Sep 2019 11:53:18 -0400 Subject: [PATCH 001/131] all: Update to truth 1.0 * Update to truth 1.0 --- android-interop-testing/app/build.gradle | 2 +- android/build.gradle | 2 +- build.gradle | 2 +- examples/android/clientcache/app/build.gradle | 2 +- repositories.bzl | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/android-interop-testing/app/build.gradle b/android-interop-testing/app/build.gradle index 1447e1a8b66..b8ea5302e86 100644 --- a/android-interop-testing/app/build.gradle +++ b/android-interop-testing/app/build.gradle @@ -66,7 +66,7 @@ dependencies { implementation ('com.google.auth:google-auth-library-oauth2-http:0.9.0') { exclude group: 'org.apache.httpcomponents', module: 'httpclient' } - implementation 'com.google.truth:truth:0.45' + implementation 'com.google.truth:truth:1.0' implementation 'javax.annotation:javax.annotation-api:1.2' implementation 'junit:junit:4.12' diff --git a/android/build.gradle b/android/build.gradle index da1c645d32e..4889c8c63b7 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -52,7 +52,7 @@ dependencies { testImplementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:3.7.1' - testImplementation 'com.google.truth:truth:0.45' + testImplementation 'com.google.truth:truth:1.0' } task javadocs(type: Javadoc) { diff --git a/build.gradle b/build.gradle index 0146c33a335..55f8cc88a7f 100644 --- a/build.gradle +++ b/build.gradle @@ -226,7 +226,7 @@ subprojects { // Test dependencies. junit: 'junit:junit:4.12', mockito: 'org.mockito:mockito-core:2.25.1', - truth: 'com.google.truth:truth:0.45', + truth: 'com.google.truth:truth:1.0', guava_testlib: "com.google.guava:guava-testlib:${guavaVersion}", // Benchmark dependencies diff --git a/examples/android/clientcache/app/build.gradle b/examples/android/clientcache/app/build.gradle index aa148322db8..b497ed64512 100644 --- a/examples/android/clientcache/app/build.gradle +++ b/examples/android/clientcache/app/build.gradle @@ -55,6 +55,6 @@ dependencies { implementation 'javax.annotation:javax.annotation-api:1.2' testImplementation 'junit:junit:4.12' - testImplementation 'com.google.truth:truth:0.45' + testImplementation 'com.google.truth:truth:1.0' testImplementation 'io.grpc:grpc-testing:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION } diff --git a/repositories.bzl b/repositories.bzl index e2c859530df..66ed0b9ac53 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -289,9 +289,9 @@ def com_google_protobuf_javalite(): def com_google_truth_truth(): jvm_maven_import_external( name = "com_google_truth_truth", - artifact = "com.google.truth:truth:0.45", + artifact = "com.google.truth:truth:1.0", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "0f7dced2a16e55a77e44fc3ff9c5be98d4bf4bb30abc18d78ffd735df950a69f", + artifact_sha256 = "edaa12f3b581fcf1c07311e94af8766919c4f3d904b00d3503147b99bf5b4004", licenses = ["notice"], # Apache 2.0 ) From 842dfa49b17085280b7d2f56b392281c319d5c3f Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Wed, 11 Sep 2019 14:00:18 -0700 Subject: [PATCH 002/131] xds: Fix a bug locality reset not fully clean up There is a bug in LocalityStore.reset() found during import. --- xds/src/main/java/io/grpc/xds/LocalityStore.java | 1 + xds/src/test/java/io/grpc/xds/LocalityStoreTest.java | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/xds/src/main/java/io/grpc/xds/LocalityStore.java b/xds/src/main/java/io/grpc/xds/LocalityStore.java index 0e2382758c3..def3b99a06b 100644 --- a/xds/src/main/java/io/grpc/xds/LocalityStore.java +++ b/xds/src/main/java/io/grpc/xds/LocalityStore.java @@ -192,6 +192,7 @@ public void reset() { for (XdsLocality locality : edsResponsLocalityInfo.keySet()) { loadStatsStore.removeLocality(locality); } + edsResponsLocalityInfo = ImmutableMap.of(); } // This is triggered by EDS response. diff --git a/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java b/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java index 4e78905b4b4..73adcc1be5d 100644 --- a/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java +++ b/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java @@ -831,6 +831,15 @@ public void reset() { verify(loadBalancers.get("sz2")).shutdown(); verify(loadStatsStore).removeLocality(locality1); verify(loadStatsStore).removeLocality(locality2); + + // Regression test for same locality added back. + localityStore.updateLocalityStore(localityInfoMap); + assertThat(loadBalancers).hasSize(2); + localityStore.reset(); + verify(loadBalancers.get("sz1")).shutdown(); + verify(loadBalancers.get("sz2")).shutdown(); + verify(loadStatsStore, times(2)).removeLocality(locality1); + verify(loadStatsStore, times(2)).removeLocality(locality2); } private static final class FakeLoadStatsStore implements LoadStatsStore { From 7f693941f8641d67b598a18006978504f3a60567 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Wed, 11 Sep 2019 14:12:58 -0700 Subject: [PATCH 003/131] xds: add test for LRS retry and re-send load reports after stream closed (#6140) * xds: add test for LRS retry and re-send load reports * Removed log verifications. --- .../io/grpc/xds/LoadReportClientImplTest.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/xds/src/test/java/io/grpc/xds/LoadReportClientImplTest.java b/xds/src/test/java/io/grpc/xds/LoadReportClientImplTest.java index e7e13494abd..6e8cad4ccd4 100644 --- a/xds/src/test/java/io/grpc/xds/LoadReportClientImplTest.java +++ b/xds/src/test/java/io/grpc/xds/LoadReportClientImplTest.java @@ -453,6 +453,78 @@ public void lrsStreamClosedAndRetried() { verify(backoffPolicy2, times(1)).nextBackoffNanos(); } + @Test + public void lrsStreamRetryAndRereport() { + verify(mockLoadReportingService).streamLoadStats(lrsResponseObserverCaptor.capture()); + StreamObserver responseObserver = lrsResponseObserverCaptor.getValue(); + assertThat(lrsRequestObservers).hasSize(1); + StreamObserver requestObserver = lrsRequestObservers.poll(); + + // First LRS request sent. + verify(requestObserver).onNext(EXPECTED_INITIAL_REQ); + assertEquals(0, fakeClock.numPendingTasks(LRS_RPC_RETRY_TASK_FILTER)); + + // Balancer sends back a normal response. + responseObserver.onNext(buildLrsResponse(100)); + + // A load reporting task is scheduled. + assertEquals(1, fakeClock.numPendingTasks(LOAD_REPORTING_TASK_FILTER)); + fakeClock.forwardNanos(99); + verifyNoMoreInteractions(requestObserver); + + // Balancer closes the stream with error. + responseObserver.onError(Status.UNKNOWN.asException()); + + // The unsent load report is cancelled. + assertEquals(0, fakeClock.numPendingTasks(LOAD_REPORTING_TASK_FILTER)); + // Will retry immediately as balancer has responded previously. + verify(mockLoadReportingService, times(2)).streamLoadStats(lrsResponseObserverCaptor.capture()); + responseObserver = lrsResponseObserverCaptor.getValue(); + assertThat(lrsRequestObservers).hasSize(1); + requestObserver = lrsRequestObservers.poll(); + InOrder inOrder = inOrder(requestObserver, loadStatsStore); + inOrder.verify(requestObserver).onNext(eq(EXPECTED_INITIAL_REQ)); + + // Balancer sends another response with a different report interval. + responseObserver.onNext(buildLrsResponse(50)); + + // Load reporting runs normally. + ClusterStats stats1 = ClusterStats.newBuilder() + .setClusterName(CLUSTER_NAME) + .setLoadReportInterval(Durations.fromNanos(50)) + .addUpstreamLocalityStats(UpstreamLocalityStats.newBuilder() + .setLocality(TEST_LOCALITY) + .setTotalRequestsInProgress(542) + .setTotalSuccessfulRequests(645) + .setTotalErrorRequests(85) + .setTotalIssuedRequests(27)) + .addDroppedRequests(DroppedRequests.newBuilder() + .setCategory("lb") + .setDroppedCount(0)) + .addDroppedRequests(DroppedRequests.newBuilder() + .setCategory("throttle") + .setDroppedCount(14)) + .setTotalDroppedRequests(14) + .build(); + ClusterStats stats2 = ClusterStats.newBuilder() + .setClusterName(CLUSTER_NAME) + .setLoadReportInterval(Durations.fromNanos(50)) + .addUpstreamLocalityStats(UpstreamLocalityStats.newBuilder() + .setLocality(TEST_LOCALITY) + .setTotalRequestsInProgress(89)) + .addDroppedRequests(DroppedRequests.newBuilder() + .setCategory("lb") + .setDroppedCount(0)) + .addDroppedRequests(DroppedRequests.newBuilder() + .setCategory("throttle") + .setDroppedCount(0)) + .setTotalDroppedRequests(0) + .build(); + when(loadStatsStore.generateLoadReport()).thenReturn(stats1, stats2); + assertNextReport(inOrder, requestObserver, stats1); + assertNextReport(inOrder, requestObserver, stats2); + } + @Test public void raceBetweenLoadReportingAndLbStreamClosure() { verify(mockLoadReportingService).streamLoadStats(lrsResponseObserverCaptor.capture()); From b092a29c5dee537c382cdd8ba1e1ac62419c7e43 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 9 Sep 2019 16:39:59 -0700 Subject: [PATCH 004/131] core: Propagate EAG Attributes in RoundRobinLoadBalancer This allows plumbing information to the subchannel via Attributes, like an authority override. RR still does not support multiple EAGs that only differ by attributes. --- .../io/grpc/util/RoundRobinLoadBalancer.java | 39 +++++++++++++------ ...AutoConfiguredLoadBalancerFactoryTest.java | 9 ++++- .../grpc/util/RoundRobinLoadBalancerTest.java | 34 +++++++--------- 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/core/src/main/java/io/grpc/util/RoundRobinLoadBalancer.java b/core/src/main/java/io/grpc/util/RoundRobinLoadBalancer.java index cab48b9e5cb..093a4c9377b 100644 --- a/core/src/main/java/io/grpc/util/RoundRobinLoadBalancer.java +++ b/core/src/main/java/io/grpc/util/RoundRobinLoadBalancer.java @@ -42,6 +42,7 @@ import io.grpc.internal.ServiceConfigUtil; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -88,9 +89,8 @@ public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { List servers = resolvedAddresses.getAddresses(); Attributes attributes = resolvedAddresses.getAttributes(); Set currentAddrs = subchannels.keySet(); - Set latestAddrs = stripAttrs(servers); - Set addedAddrs = setsDifference(latestAddrs, currentAddrs); - Set removedAddrs = setsDifference(currentAddrs, latestAddrs); + Map latestAddrs = stripAttrs(servers); + Set removedAddrs = setsDifference(currentAddrs, latestAddrs.keySet()); Map serviceConfig = attributes.get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG); if (serviceConfig != null) { @@ -109,8 +109,18 @@ public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { } } - // Create new subchannels for new addresses. - for (EquivalentAddressGroup addressGroup : addedAddrs) { + for (Map.Entry latestEntry : + latestAddrs.entrySet()) { + EquivalentAddressGroup strippedAddressGroup = latestEntry.getKey(); + EquivalentAddressGroup originalAddressGroup = latestEntry.getValue(); + Subchannel existingSubchannel = subchannels.get(strippedAddressGroup); + if (existingSubchannel != null) { + // EAG's Attributes may have changed. + existingSubchannel.updateAddresses(Collections.singletonList(originalAddressGroup)); + continue; + } + // Create new subchannels for new addresses. + // NB(lukaszx0): we don't merge `attributes` with `subchannelAttr` because subchannel // doesn't need them. They're describing the resolved server list but we're not taking // any action based on this information. @@ -128,7 +138,7 @@ public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { final Subchannel subchannel = checkNotNull( helper.createSubchannel(CreateSubchannelArgs.newBuilder() - .setAddresses(addressGroup) + .setAddresses(originalAddressGroup) .setAttributes(subchannelAttrs.build()) .build()), "subchannel"); @@ -141,7 +151,7 @@ public void onSubchannelState(ConnectivityStateInfo state) { if (stickyRef != null) { stickyRef.value = subchannel; } - subchannels.put(addressGroup, subchannel); + subchannels.put(strippedAddressGroup, subchannel); subchannel.requestConnection(); } @@ -168,7 +178,7 @@ public void handleNameResolutionError(Status error) { } private void processSubchannelState(Subchannel subchannel, ConnectivityStateInfo stateInfo) { - if (subchannels.get(subchannel.getAddresses()) != subchannel) { + if (subchannels.get(stripAttrs(subchannel.getAddresses())) != subchannel) { return; } if (stateInfo.getState() == SHUTDOWN && stickinessState != null) { @@ -257,16 +267,21 @@ private static List filterNonFailingSubchannels( /** * Converts list of {@link EquivalentAddressGroup} to {@link EquivalentAddressGroup} set and - * remove all attributes. + * remove all attributes. The values are the original EAGs. */ - private static Set stripAttrs(List groupList) { - Set addrs = new HashSet<>(groupList.size()); + private static Map stripAttrs( + List groupList) { + Map addrs = new HashMap<>(groupList.size() * 2); for (EquivalentAddressGroup group : groupList) { - addrs.add(new EquivalentAddressGroup(group.getAddresses())); + addrs.put(stripAttrs(group), group); } return addrs; } + private static EquivalentAddressGroup stripAttrs(EquivalentAddressGroup eag) { + return new EquivalentAddressGroup(eag.getAddresses()); + } + @VisibleForTesting Collection getSubchannels() { return subchannels.values(); diff --git a/core/src/test/java/io/grpc/internal/AutoConfiguredLoadBalancerFactoryTest.java b/core/src/test/java/io/grpc/internal/AutoConfiguredLoadBalancerFactoryTest.java index 251bc5641a4..496d2ca50e8 100644 --- a/core/src/test/java/io/grpc/internal/AutoConfiguredLoadBalancerFactoryTest.java +++ b/core/src/test/java/io/grpc/internal/AutoConfiguredLoadBalancerFactoryTest.java @@ -34,6 +34,7 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import com.google.common.base.Preconditions; import io.grpc.Attributes; import io.grpc.ChannelLogger; import io.grpc.ChannelLogger.ChannelLogLevel; @@ -851,7 +852,7 @@ private static class TestSubchannel extends Subchannel { this.attrs = args.getAttributes(); } - final List addrs; + List addrs; final Attributes attrs; @Override @@ -875,6 +876,12 @@ public List getAllAddresses() { public Attributes getAttributes() { return attrs; } + + @Override + public void updateAddresses(List addrs) { + Preconditions.checkNotNull(addrs, "addrs"); + this.addrs = addrs; + } } private static final class FakeLoadBalancerProvider extends LoadBalancerProvider { diff --git a/core/src/test/java/io/grpc/util/RoundRobinLoadBalancerTest.java b/core/src/test/java/io/grpc/util/RoundRobinLoadBalancerTest.java index a9895df9547..90c9acb2fc8 100644 --- a/core/src/test/java/io/grpc/util/RoundRobinLoadBalancerTest.java +++ b/core/src/test/java/io/grpc/util/RoundRobinLoadBalancerTest.java @@ -195,25 +195,22 @@ public void pickAfterResolvedUpdatedHosts() throws Exception { Subchannel oldSubchannel = mock(Subchannel.class); Subchannel newSubchannel = mock(Subchannel.class); + Attributes.Key key = Attributes.Key.create("check-that-it-is-propagated"); FakeSocketAddress removedAddr = new FakeSocketAddress("removed"); + EquivalentAddressGroup removedEag = new EquivalentAddressGroup(removedAddr); FakeSocketAddress oldAddr = new FakeSocketAddress("old"); + EquivalentAddressGroup oldEag1 = new EquivalentAddressGroup(oldAddr); + EquivalentAddressGroup oldEag2 = new EquivalentAddressGroup( + oldAddr, Attributes.newBuilder().set(key, "oldattr").build()); FakeSocketAddress newAddr = new FakeSocketAddress("new"); + EquivalentAddressGroup newEag = new EquivalentAddressGroup( + newAddr, Attributes.newBuilder().set(key, "newattr").build()); - List allSubchannels = - Lists.newArrayList(removedSubchannel, oldSubchannel, newSubchannel); - List allAddrs = - Lists.newArrayList(removedAddr, oldAddr, newAddr); - for (int i = 0; i < allSubchannels.size(); i++) { - Subchannel subchannel = allSubchannels.get(i); - List eagList = - Arrays.asList(new EquivalentAddressGroup(allAddrs.get(i))); - subchannels.put(eagList, subchannel); - } + subchannels.put(Collections.singletonList(removedEag), removedSubchannel); + subchannels.put(Collections.singletonList(oldEag1), oldSubchannel); + subchannels.put(Collections.singletonList(newEag), newSubchannel); - List currentServers = - Lists.newArrayList( - new EquivalentAddressGroup(removedAddr), - new EquivalentAddressGroup(oldAddr)); + List currentServers = Lists.newArrayList(removedEag, oldEag1); InOrder inOrder = inOrder(mockHelper); @@ -236,15 +233,14 @@ public void pickAfterResolvedUpdatedHosts() throws Exception { assertThat(loadBalancer.getSubchannels()).containsExactly(removedSubchannel, oldSubchannel); - List latestServers = - Lists.newArrayList( - new EquivalentAddressGroup(oldAddr), - new EquivalentAddressGroup(newAddr)); -; + // This time with Attributes + List latestServers = Lists.newArrayList(oldEag2, newEag); + loadBalancer.handleResolvedAddresses( ResolvedAddresses.newBuilder().setAddresses(latestServers).setAttributes(affinity).build()); verify(newSubchannel, times(1)).requestConnection(); + verify(oldSubchannel, times(1)).updateAddresses(Arrays.asList(oldEag2)); verify(removedSubchannel, times(1)).shutdown(); deliverSubchannelState(removedSubchannel, ConnectivityStateInfo.forNonError(SHUTDOWN)); From 132e8bc8dd1876ab67fb2ede8d98d6e4aa225059 Mon Sep 17 00:00:00 2001 From: edr Date: Thu, 12 Sep 2019 05:35:18 +0200 Subject: [PATCH 005/131] core: Add Attributes.Key for authority in EquivalentAddressGroup (#6126) This enables NameResolvers to dynamically provide authority for each Subchannel Fixes #4469 --- .../java/io/grpc/EquivalentAddressGroup.java | 7 +++++++ .../io/grpc/internal/InternalSubchannel.java | 7 +++++-- .../io/grpc/internal/InternalSubchannelTest.java | 16 ++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/io/grpc/EquivalentAddressGroup.java b/api/src/main/java/io/grpc/EquivalentAddressGroup.java index 3c48c938bb2..2fa1099e249 100644 --- a/api/src/main/java/io/grpc/EquivalentAddressGroup.java +++ b/api/src/main/java/io/grpc/EquivalentAddressGroup.java @@ -35,6 +35,13 @@ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770") public final class EquivalentAddressGroup { + /** + * The authority to be used when constructing Subchannels for this EquivalentAddressGroup. + */ + @Attr + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6138") + public static final Attributes.Key ATTR_AUTHORITY_OVERRIDE = + Attributes.Key.create("io.grpc.EquivalentAddressGroup.authorityOverride"); private final List addrs; private final Attributes attrs; diff --git a/core/src/main/java/io/grpc/internal/InternalSubchannel.java b/core/src/main/java/io/grpc/internal/InternalSubchannel.java index d9474528666..d84c7710384 100644 --- a/core/src/main/java/io/grpc/internal/InternalSubchannel.java +++ b/core/src/main/java/io/grpc/internal/InternalSubchannel.java @@ -231,10 +231,13 @@ private void startNewTransport() { address = proxiedAddr.getTargetAddress(); } + Attributes currentEagAttributes = addressIndex.getCurrentEagAttributes(); + String eagChannelAuthority = currentEagAttributes + .get(EquivalentAddressGroup.ATTR_AUTHORITY_OVERRIDE); ClientTransportFactory.ClientTransportOptions options = new ClientTransportFactory.ClientTransportOptions() - .setAuthority(authority) - .setEagAttributes(addressIndex.getCurrentEagAttributes()) + .setAuthority(eagChannelAuthority != null ? eagChannelAuthority : authority) + .setEagAttributes(currentEagAttributes) .setUserAgent(userAgent) .setHttpConnectProxiedSocketAddress(proxiedAddr); TransportLogger transportLogger = new TransportLogger(); diff --git a/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java b/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java index 4d942954b9b..985be0f68a9 100644 --- a/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java +++ b/core/src/test/java/io/grpc/internal/InternalSubchannelTest.java @@ -176,6 +176,22 @@ public void constructor_eagListWithNull_throws() { isA(TransportLogger.class)); } + @Test public void eagAuthorityOverride_propagatesToTransport() { + SocketAddress addr = new SocketAddress() {}; + String overriddenAuthority = "authority-override"; + Attributes attr = Attributes.newBuilder() + .set(EquivalentAddressGroup.ATTR_AUTHORITY_OVERRIDE, overriddenAuthority).build(); + createInternalSubchannel(new EquivalentAddressGroup(Arrays.asList(addr), attr)); + + // First attempt + assertNull(internalSubchannel.obtainActiveTransport()); + assertEquals(CONNECTING, internalSubchannel.getState()); + verify(mockTransportFactory).newClientTransport( + eq(addr), + eq(createClientTransportOptions().setAuthority(overriddenAuthority).setEagAttributes(attr)), + isA(TransportLogger.class)); + } + @Test public void singleAddressReconnect() { SocketAddress addr = mock(SocketAddress.class); createInternalSubchannel(addr); From cf3e2c4ef17e733dd97d9b8dca04e040ab4d29dd Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 12 Sep 2019 13:17:35 -0700 Subject: [PATCH 006/131] auth: Avoid com.auth0:java-jwt dependency in test --- auth/build.gradle | 3 +-- .../GoogleAuthLibraryCallCredentialsTest.java | 21 +++++++++++-------- build.gradle | 1 - 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/auth/build.gradle b/auth/build.gradle index 0d1ad372d7a..09619ea562c 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -3,8 +3,7 @@ dependencies { compile project(':grpc-api'), libraries.google_auth_credentials testCompile project(':grpc-testing'), - libraries.google_auth_oauth2_http, - libraries.jwt + libraries.google_auth_oauth2_http signature "org.codehaus.mojo.signature:java17:1.0@signature" signature "net.sf.androidscents.signature:android-api-level-14:4.0_r4@signature" } diff --git a/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java b/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java index fed11b70eea..bb1a569abf9 100644 --- a/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java +++ b/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java @@ -28,8 +28,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.auth0.jwt.JWT; -import com.auth0.jwt.interfaces.DecodedJWT; import com.google.auth.Credentials; import com.google.auth.RequestMetadataCallback; import com.google.auth.oauth2.AccessToken; @@ -40,6 +38,7 @@ import com.google.common.collect.LinkedListMultimap; import com.google.common.collect.ListMultimap; import com.google.common.collect.Multimaps; +import com.google.common.io.BaseEncoding; import io.grpc.Attributes; import io.grpc.CallCredentials; import io.grpc.CallCredentials.MetadataApplier; @@ -47,6 +46,7 @@ import io.grpc.MethodDescriptor; import io.grpc.SecurityLevel; import io.grpc.Status; +import io.grpc.internal.JsonParser; import io.grpc.testing.TestMethodDescriptors; import java.io.IOException; import java.net.URI; @@ -408,13 +408,16 @@ public void jwtAccessCredentialsInRequestMetadata() throws Exception { verify(applier).apply(headersCaptor.capture()); Metadata headers = headersCaptor.getValue(); String token = - Iterables.getOnlyElement(headers.getAll(AUTHORIZATION)).substring("Bearer".length()); - DecodedJWT decoded = JWT.decode(token); - assertEquals("test-private-key-id", decoded.getKeyId()); - assertEquals("https://example.com:123/a.service", - Iterables.getOnlyElement(decoded.getAudience())); - assertEquals("test-email@example.com", decoded.getIssuer()); - assertEquals("test-email@example.com", decoded.getSubject()); + Iterables.getOnlyElement(headers.getAll(AUTHORIZATION)).substring("Bearer ".length()); + String[] parts = token.split("\\.", 3); + String jsonHeader = new String(BaseEncoding.base64Url().decode(parts[0]), US_ASCII); + String jsonPayload = new String(BaseEncoding.base64Url().decode(parts[1]), US_ASCII); + Map header = (Map) JsonParser.parse(jsonHeader); + assertEquals("test-private-key-id", header.get("kid")); + Map payload = (Map) JsonParser.parse(jsonPayload); + assertEquals("https://example.com:123/a.service", payload.get("aud")); + assertEquals("test-email@example.com", payload.get("iss")); + assertEquals("test-email@example.com", payload.get("sub")); } private int runPendingRunnables() { diff --git a/build.gradle b/build.gradle index 55f8cc88a7f..8336fb222f5 100644 --- a/build.gradle +++ b/build.gradle @@ -191,7 +191,6 @@ subprojects { hpack: 'com.twitter:hpack:0.10.1', javax_annotation: 'javax.annotation:javax.annotation-api:1.2', jsr305: 'com.google.code.findbugs:jsr305:3.0.2', - jwt: 'com.auth0:java-jwt:3.8.2', google_api_protos: 'com.google.api.grpc:proto-google-common-protos:1.12.0', google_auth_credentials: "com.google.auth:google-auth-library-credentials:${googleauthVersion}", google_auth_oauth2_http: "com.google.auth:google-auth-library-oauth2-http:${googleauthVersion}", From 3c3a823a81f0756b5bcb614280269167786497cd Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 08:18:57 -0700 Subject: [PATCH 007/131] Swap to Gradle's Plugin DSL for much of build Examples and android projects were left unchanged. They can be changed later. No plugin versions were changed, to make this as non-functional of a change as possible. Upgrading Gradle to 5.6 was necessary for pluginManagement in settings.gradle. --- all/build.gradle | 12 +++--------- alts/build.gradle | 16 +++------------- benchmarks/build.gradle | 12 ++++-------- build.gradle | 20 ++++++-------------- compiler/build.gradle | 16 +++++----------- gae-interop-testing/gae-jdk8/build.gradle | 10 +++++++--- gradle/wrapper/gradle-wrapper.properties | 2 +- grpclb/build.gradle | 12 ++++-------- interop-testing/build.gradle | 15 +++++---------- netty/shaded/build.gradle | 7 ++----- protobuf-lite/build.gradle | 11 ++--------- protobuf/build.gradle | 12 ++++-------- services/build.gradle | 9 ++------- settings.gradle | 13 +++++++++++++ testing-proto/build.gradle | 13 ++++--------- xds/build.gradle | 17 +++-------------- 16 files changed, 68 insertions(+), 129 deletions(-) diff --git a/all/build.gradle b/all/build.gradle index 262b0d1730f..3df9132c094 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -1,15 +1,9 @@ -apply plugin: 'com.github.kt3k.coveralls' +plugins { + id "com.github.kt3k.coveralls" +} description = "gRPC: All" -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath 'org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.0.1' } -} - def subprojects = [ project(':grpc-api'), project(':grpc-auth'), diff --git a/alts/build.gradle b/alts/build.gradle index d71f58f9d8f..1d3ed8ab8bb 100644 --- a/alts/build.gradle +++ b/alts/build.gradle @@ -1,23 +1,13 @@ -buildscript { - repositories { jcenter() } - dependencies { classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' } +plugins { + id "com.github.johnrengelman.shadow" + id "com.google.protobuf" } -apply plugin: 'com.github.johnrengelman.shadow' - description = "gRPC: ALTS" sourceCompatibility = 1.7 targetCompatibility = 1.7 -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } -} - dependencies { compile project(':grpc-auth'), project(':grpc-core'), diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index cc7a9a6c176..2bfac4672bd 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -1,12 +1,8 @@ -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } -} +plugins { + id "application" -apply plugin: 'application' + id "com.google.protobuf" +} description = "grpc Benchmarks" diff --git a/build.gradle b/build.gradle index 8336fb222f5..83fc1cb996d 100644 --- a/build.gradle +++ b/build.gradle @@ -1,15 +1,9 @@ -buildscript { - repositories { - mavenLocal() - maven { url "https://plugins.gradle.org/m2/" } - } - dependencies { - classpath 'com.google.gradle:osdetector-gradle-plugin:1.4.0' - classpath 'ru.vyarus:gradle-animalsniffer-plugin:1.5.0' - classpath 'net.ltgt.gradle:gradle-errorprone-plugin:0.8.1' - classpath "me.champeau.gradle:jmh-gradle-plugin:0.4.5" - classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.2.5' - } +plugins { + id "com.google.osdetector" apply false + id "me.champeau.gradle.japicmp" apply false + id "me.champeau.gradle.jmh" apply false + id "net.ltgt.errorprone" apply false + id "ru.vyarus.animalsniffer" apply false } import net.ltgt.gradle.errorprone.CheckSeverity @@ -115,7 +109,6 @@ subprojects { configureProtoCompilation = { String generatedSourcePath = "${projectDir}/src/generated" - project.apply plugin: 'com.google.protobuf' project.protobuf { protoc { if (project.hasProperty('protoc')) { @@ -205,7 +198,6 @@ subprojects { protobuf: "com.google.protobuf:protobuf-java:${protobufVersion}", protobuf_lite: "com.google.protobuf:protobuf-lite:3.0.1", protoc_lite: "com.google.protobuf:protoc-gen-javalite:3.0.0", - protobuf_plugin: 'com.google.protobuf:protobuf-gradle-plugin:0.8.8', protobuf_util: "com.google.protobuf:protobuf-java-util:${protobufVersion}", lang: "org.apache.commons:commons-lang3:3.5", diff --git a/compiler/build.gradle b/compiler/build.gradle index cfe037d12b9..a57fd41bc31 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -1,17 +1,11 @@ -apply plugin: "cpp" -apply plugin: "com.google.protobuf" +plugins { + id "cpp" -description = 'The protoc plugin for gRPC Java' - -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - mavenLocal() - } - dependencies { classpath libraries.protobuf_plugin } + id "com.google.protobuf" } +description = 'The protoc plugin for gRPC Java' + def artifactStagingPath = "$buildDir/artifacts" as File // Adds space-delimited arguments from the environment variable env to the // argList. diff --git a/gae-interop-testing/gae-jdk8/build.gradle b/gae-interop-testing/gae-jdk8/build.gradle index 69f48bd08fd..53befa72e4c 100644 --- a/gae-interop-testing/gae-jdk8/build.gradle +++ b/gae-interop-testing/gae-jdk8/build.gradle @@ -11,7 +11,6 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -description = 'gRPC: gae interop testing (jdk8)' buildscript { // Configuration for building @@ -26,6 +25,13 @@ buildscript { } } +plugins { + id "java" + id "war" +} + +description = 'gRPC: gae interop testing (jdk8)' + repositories { // repositories for Jar's you access in your code mavenLocal() @@ -34,8 +40,6 @@ repositories { jcenter() } -apply plugin: 'java' // standard Java tasks -apply plugin: 'war' // standard Web Archive plugin apply plugin: 'com.google.cloud.tools.appengine' // App Engine tasks dependencies { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f4d7b2bf616..7c4388a9216 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/grpclb/build.gradle b/grpclb/build.gradle index e141bcd346a..2e67844e7dd 100644 --- a/grpclb/build.gradle +++ b/grpclb/build.gradle @@ -1,13 +1,9 @@ -description = "gRPC: GRPCLB LoadBalancer plugin" - -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } +plugins { + id "com.google.protobuf" } +description = "gRPC: GRPCLB LoadBalancer plugin" + dependencies { compile project(':grpc-core'), project(':grpc-protobuf'), diff --git a/interop-testing/build.gradle b/interop-testing/build.gradle index 775b4ccc88d..33e880f9e61 100644 --- a/interop-testing/build.gradle +++ b/interop-testing/build.gradle @@ -1,17 +1,12 @@ -apply plugin: 'application' +plugins { + id "application" + + id "com.google.protobuf" +} description = "gRPC: Integration Testing" startScripts.enabled = false -// Add dependency on the protobuf plugin -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } -} - dependencies { compile project(':grpc-alts'), project(':grpc-auth'), diff --git a/netty/shaded/build.gradle b/netty/shaded/build.gradle index f40268ee802..b7f6ec73d6f 100644 --- a/netty/shaded/build.gradle +++ b/netty/shaded/build.gradle @@ -1,10 +1,7 @@ -buildscript { - repositories { jcenter() } - dependencies { classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' } +plugins { + id "com.github.johnrengelman.shadow" } -apply plugin: 'com.github.johnrengelman.shadow' - description = "gRPC: Netty Shaded" sourceSets { testShadow {} } diff --git a/protobuf-lite/build.gradle b/protobuf-lite/build.gradle index 74f75c6aa82..a319a182cbd 100644 --- a/protobuf-lite/build.gradle +++ b/protobuf-lite/build.gradle @@ -1,14 +1,7 @@ -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - mavenLocal() - } - dependencies { classpath libraries.protobuf_plugin } +plugins { + id "com.google.protobuf" } -apply plugin: 'com.google.protobuf' - description = 'gRPC: Protobuf Lite' dependencies { diff --git a/protobuf/build.gradle b/protobuf/build.gradle index eb8efb38a31..b4204bd6311 100644 --- a/protobuf/build.gradle +++ b/protobuf/build.gradle @@ -1,13 +1,9 @@ -description = 'gRPC: Protobuf' - -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } +plugins { + id "com.google.protobuf" } +description = 'gRPC: Protobuf' + dependencies { compile project(':grpc-api'), libraries.protobuf diff --git a/services/build.gradle b/services/build.gradle index 9c87031d269..739b2d9f279 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -1,10 +1,5 @@ -// Add dependency on the protobuf plugin -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } +plugins { + id "com.google.protobuf" } description = "gRPC: Services" diff --git a/settings.gradle b/settings.gradle index eac88a317be..3f9a7e6ef13 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,16 @@ +pluginManagement { + plugins { + id "com.github.johnrengelman.shadow" version "2.0.4" + id "com.github.kt3k.coveralls" version "2.0.1" + id "com.google.osdetector" version "1.4.0" + id "com.google.protobuf" version "0.8.8" + id "me.champeau.gradle.japicmp" version "0.2.5" + id "me.champeau.gradle.jmh" version "0.4.5" + id "net.ltgt.errorprone" version "0.8.1" + id "ru.vyarus.animalsniffer" version "1.5.0" + } +} + rootProject.name = "grpc" include ":grpc-api" include ":grpc-core" diff --git a/testing-proto/build.gradle b/testing-proto/build.gradle index 144c06d3ac3..6a09b2f7783 100644 --- a/testing-proto/build.gradle +++ b/testing-proto/build.gradle @@ -1,14 +1,9 @@ -description = "gRPC: Testing Protos" - -// Add dependency on the protobuf plugin -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - } - dependencies { classpath libraries.protobuf_plugin } +plugins { + id "com.google.protobuf" } +description = "gRPC: Testing Protos" + dependencies { compile project(':grpc-protobuf'), project(':grpc-stub') diff --git a/xds/build.gradle b/xds/build.gradle index db4d5255bb1..9aaadcff7c2 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -1,18 +1,8 @@ -// Add dependency on the protobuf plugin -buildscript { - repositories { - maven { // The google mirror is less flaky than mavenCentral() - url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } - gradlePluginPortal() - } - dependencies { - classpath libraries.protobuf_plugin - classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' - } +plugins { + id "com.github.johnrengelman.shadow" + id "com.google.protobuf" } -apply plugin: 'com.github.johnrengelman.shadow' - description = "gRPC: XDS plugin" [compileJava].each() { @@ -42,7 +32,6 @@ dependencies { signature "org.codehaus.mojo.signature:java17:1.0@signature" } -apply plugin: 'com.google.protobuf' sourceSets { main { proto { From 55ac6f08afb62e7685cbe57da9b486f266da0337 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 09:03:53 -0700 Subject: [PATCH 008/131] Apply JMH plugin explicitly when needed --- api/build.gradle | 4 ++++ benchmarks/build.gradle | 1 + build.gradle | 51 ++++++++++++++++++----------------------- context/build.gradle | 4 ++++ core/build.gradle | 4 ++++ netty/build.gradle | 4 ++++ 6 files changed, 39 insertions(+), 29 deletions(-) diff --git a/api/build.gradle b/api/build.gradle index 7c399d243c3..5b50e3da7f0 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "me.champeau.gradle.jmh" +} + description = 'gRPC: API' dependencies { diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index 2bfac4672bd..f5e284031de 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -2,6 +2,7 @@ plugins { id "application" id "com.google.protobuf" + id "me.champeau.gradle.jmh" } description = "grpc Benchmarks" diff --git a/build.gradle b/build.gradle index 83fc1cb996d..7fc0360ee14 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,6 @@ plugins { id "com.google.osdetector" apply false id "me.champeau.gradle.japicmp" apply false - id "me.champeau.gradle.jmh" apply false id "net.ltgt.errorprone" apply false id "ru.vyarus.animalsniffer" apply false } @@ -17,7 +16,6 @@ subprojects { apply plugin: "signing" apply plugin: "jacoco" - apply plugin: "me.champeau.gradle.jmh" apply plugin: "com.google.osdetector" // The plugin only has an effect if a signature is specified apply plugin: "ru.vyarus.animalsniffer" @@ -53,11 +51,7 @@ subprojects { mavenLocal() } - [ - compileJava, - compileTestJava, - compileJmhJava - ].each() { + tasks.withType(JavaCompile) { it.options.compilerArgs += [ "-Xlint:all", "-Xlint:-options", @@ -160,11 +154,7 @@ subprojects { } } - [ - compileJava, - compileTestJava, - compileJmhJava - ].each() { + tasks.withType(JavaCompile) { // Protobuf-generated code produces some warnings. // https://github.com/google/protobuf/issues/2718 it.options.compilerArgs += [ @@ -253,9 +243,6 @@ subprojects { // Configuration for modules that use Jetty ALPN agent alpnagent libraries.jetty_alpn_agent - - jmh 'org.openjdk.jmh:jmh-core:1.19', - 'org.openjdk.jmh:jmh-generator-bytecode:1.19' } // Disable JavaDoc doclint on Java 8. It's annoying. @@ -295,20 +282,26 @@ subprojects { source = fileTree(dir: "src/test", include: "**/*.java") } - // invoke jmh on a single benchmark class like so: - // ./gradlew -PjmhIncludeSingleClass=StatsTraceContextBenchmark clean :grpc-core:jmh - jmh { - warmupIterations = 10 - iterations = 10 - fork = 1 - // None of our benchmarks need the tests, and we have pseudo-circular - // dependencies that break when including them. (context's testCompile - // depends on core; core's testCompile depends on testing) - includeTests = false - if (project.hasProperty('jmhIncludeSingleClass')) { - include = [ - project.property('jmhIncludeSingleClass') - ] + plugins.withId("me.champeau.gradle.jmh") { + dependencies { + jmh 'org.openjdk.jmh:jmh-core:1.19', + 'org.openjdk.jmh:jmh-generator-bytecode:1.19' + } + // invoke jmh on a single benchmark class like so: + // ./gradlew -PjmhIncludeSingleClass=StatsTraceContextBenchmark clean :grpc-core:jmh + jmh { + warmupIterations = 10 + iterations = 10 + fork = 1 + // None of our benchmarks need the tests, and we have pseudo-circular + // dependencies that break when including them. (context's testCompile + // depends on core; core's testCompile depends on testing) + includeTests = false + if (project.hasProperty('jmhIncludeSingleClass')) { + include = [ + project.property('jmhIncludeSingleClass') + ] + } } } diff --git a/context/build.gradle b/context/build.gradle index 1513cbcb886..e504f5de577 100644 --- a/context/build.gradle +++ b/context/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "me.champeau.gradle.jmh" +} + description = 'gRPC: Context' dependencies { diff --git a/core/build.gradle b/core/build.gradle index 4202f881162..ce215d1f884 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "me.champeau.gradle.jmh" +} + description = 'gRPC: Core' dependencies { diff --git a/netty/build.gradle b/netty/build.gradle index 6b5954cd941..8afe46da187 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "me.champeau.gradle.jmh" +} + description = "gRPC: Netty" dependencies { compile project(':grpc-core'), From 5b838e52844d86d3cedc5009a123d009c6e4b66d Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 09:27:32 -0700 Subject: [PATCH 009/131] Apply maven-publish plugin explicitly when needed --- all/build.gradle | 2 + alts/build.gradle | 2 + api/build.gradle | 2 + auth/build.gradle | 4 + benchmarks/build.gradle | 1 + bom/build.gradle | 4 + build.gradle | 163 +++++++++++++++++------------------ compiler/build.gradle | 1 + context/build.gradle | 2 + core/build.gradle | 2 + grpclb/build.gradle | 2 + interop-testing/build.gradle | 1 + netty/build.gradle | 2 + netty/shaded/build.gradle | 2 + okhttp/build.gradle | 4 + protobuf-lite/build.gradle | 2 + protobuf/build.gradle | 2 + services/build.gradle | 2 + stub/build.gradle | 4 + testing-proto/build.gradle | 2 + testing/build.gradle | 4 + xds/build.gradle | 3 + 22 files changed, 130 insertions(+), 83 deletions(-) diff --git a/all/build.gradle b/all/build.gradle index 3df9132c094..5cd86feb47e 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.github.kt3k.coveralls" } diff --git a/alts/build.gradle b/alts/build.gradle index 1d3ed8ab8bb..4b06db9e5d3 100644 --- a/alts/build.gradle +++ b/alts/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.github.johnrengelman.shadow" id "com.google.protobuf" } diff --git a/api/build.gradle b/api/build.gradle index 5b50e3da7f0..ce4662904c3 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "me.champeau.gradle.jmh" } diff --git a/auth/build.gradle b/auth/build.gradle index 09619ea562c..85509f51dfc 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "maven-publish" +} + description = "gRPC: Auth" dependencies { compile project(':grpc-api'), diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index f5e284031de..a31d55b2d31 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -1,5 +1,6 @@ plugins { id "application" + id "maven-publish" id "com.google.protobuf" id "me.champeau.gradle.jmh" diff --git a/bom/build.gradle b/bom/build.gradle index 8c1d30b9506..dd22c7e7ae5 100644 --- a/bom/build.gradle +++ b/bom/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "maven-publish" +} + description = 'gRPC: BOM' publishing { diff --git a/build.gradle b/build.gradle index 7fc0360ee14..5360313afd3 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,6 @@ subprojects { apply plugin: "checkstyle" apply plugin: "java" apply plugin: "maven" - apply plugin: "maven-publish" apply plugin: "idea" apply plugin: "signing" apply plugin: "jacoco" @@ -305,109 +304,107 @@ subprojects { } } - task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc - } - - task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource - } - - publishing { - publications { - // do not use mavenJava, as java plugin will modify it via "magic" - maven(MavenPublication) { - if (project.name != 'grpc-netty-shaded') { - from components.java - } + plugins.withId("maven-publish") { + task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc + } - artifact javadocJar - artifact sourcesJar + task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allSource + } - pom { - name = project.group + ":" + project.name - url = 'https://github.com/grpc/grpc-java' - afterEvaluate { - // description is not available until evaluated. - description = project.description + publishing { + publications { + // do not use mavenJava, as java plugin will modify it via "magic" + maven(MavenPublication) { + if (project.name != 'grpc-netty-shaded') { + from components.java } - scm { - connection = 'scm:git:https://github.com/grpc/grpc-java.git' - developerConnection = 'scm:git:git@github.com:grpc/grpc-java.git' + artifact javadocJar + artifact sourcesJar + + pom { + name = project.group + ":" + project.name url = 'https://github.com/grpc/grpc-java' - } + afterEvaluate { + // description is not available until evaluated. + description = project.description + } - licenses { - license { - name = 'Apache 2.0' - url = 'https://opensource.org/licenses/Apache-2.0' + scm { + connection = 'scm:git:https://github.com/grpc/grpc-java.git' + developerConnection = 'scm:git:git@github.com:grpc/grpc-java.git' + url = 'https://github.com/grpc/grpc-java' } - } - developers { - developer { - id = "grpc.io" - name = "gRPC Contributors" - email = "grpc-io@googlegroups.com" - url = "https://grpc.io/" - organization = "gRPC Authors" - organizationUrl = "https://www.google.com" + licenses { + license { + name = 'Apache 2.0' + url = 'https://opensource.org/licenses/Apache-2.0' + } } - } - withXml { - if (!(project.name in - [ - "grpc-stub", - "grpc-protobuf", - "grpc-protobuf-lite", - ])) { - asNode().dependencies.'*'.findAll() { dep -> - dep.artifactId.text() in ['grpc-api', 'grpc-core'] - }.each() { core -> - core.version*.value = "[" + core.version.text() + "]" + developers { + developer { + id = "grpc.io" + name = "gRPC Contributors" + email = "grpc-io@googlegroups.com" + url = "https://grpc.io/" + organization = "gRPC Authors" + organizationUrl = "https://www.google.com" + } + } + + withXml { + if (!(project.name in + [ + "grpc-stub", + "grpc-protobuf", + "grpc-protobuf-lite", + ])) { + asNode().dependencies.'*'.findAll() { dep -> + dep.artifactId.text() in ['grpc-api', 'grpc-core'] + }.each() { core -> + core.version*.value = "[" + core.version.text() + "]" + } } } } } } - } - repositories { - maven { - if (rootProject.hasProperty('repositoryDir')) { - url = new File(rootProject.repositoryDir).toURI() - } else { - String stagingUrl - if (rootProject.hasProperty('repositoryId')) { - stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' + - rootProject.repositoryId + repositories { + maven { + if (rootProject.hasProperty('repositoryDir')) { + url = new File(rootProject.repositoryDir).toURI() } else { - stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' - } - credentials { - if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) { - username = rootProject.ossrhUsername - password = rootProject.ossrhPassword + String stagingUrl + if (rootProject.hasProperty('repositoryId')) { + stagingUrl = 'https://oss.sonatype.org/service/local/staging/deployByRepositoryId/' + + rootProject.repositoryId + } else { + stagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2/' + } + credentials { + if (rootProject.hasProperty('ossrhUsername') && rootProject.hasProperty('ossrhPassword')) { + username = rootProject.ossrhUsername + password = rootProject.ossrhPassword + } } + def releaseUrl = stagingUrl + def snapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' + url = version.endsWith('SNAPSHOT') ? snapshotUrl : releaseUrl } - def releaseUrl = stagingUrl - def snapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots/' - url = version.endsWith('SNAPSHOT') ? snapshotUrl : releaseUrl - } + } } } - } - signing { - required false - sign publishing.publications.maven - } - - [publishMavenPublicationToMavenRepository, publishMavenPublicationToMavenLocal]*.onlyIf { - !name.contains("grpc-gae-interop-testing") && !name.contains("grpc-xds") + signing { + required false + sign publishing.publications.maven + } } // At a test failure, log the stack trace to the console so that we don't diff --git a/compiler/build.gradle b/compiler/build.gradle index a57fd41bc31..1b0a21037fb 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -1,5 +1,6 @@ plugins { id "cpp" + id "maven-publish" id "com.google.protobuf" } diff --git a/context/build.gradle b/context/build.gradle index e504f5de577..b2c3c4d5a18 100644 --- a/context/build.gradle +++ b/context/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "me.champeau.gradle.jmh" } diff --git a/core/build.gradle b/core/build.gradle index ce215d1f884..f9b81a0a977 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "me.champeau.gradle.jmh" } diff --git a/grpclb/build.gradle b/grpclb/build.gradle index 2e67844e7dd..7488fd0b52b 100644 --- a/grpclb/build.gradle +++ b/grpclb/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.google.protobuf" } diff --git a/interop-testing/build.gradle b/interop-testing/build.gradle index 33e880f9e61..a1709c1964e 100644 --- a/interop-testing/build.gradle +++ b/interop-testing/build.gradle @@ -1,5 +1,6 @@ plugins { id "application" + id "maven-publish" id "com.google.protobuf" } diff --git a/netty/build.gradle b/netty/build.gradle index 8afe46da187..60b7d8a750f 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "me.champeau.gradle.jmh" } diff --git a/netty/shaded/build.gradle b/netty/shaded/build.gradle index b7f6ec73d6f..609e6c3c28d 100644 --- a/netty/shaded/build.gradle +++ b/netty/shaded/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.github.johnrengelman.shadow" } diff --git a/okhttp/build.gradle b/okhttp/build.gradle index 7ee7fed4c58..5b6fd6d4689 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "maven-publish" +} + description = "gRPC: OkHttp" dependencies { diff --git a/protobuf-lite/build.gradle b/protobuf-lite/build.gradle index a319a182cbd..49d42570c0e 100644 --- a/protobuf-lite/build.gradle +++ b/protobuf-lite/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.google.protobuf" } diff --git a/protobuf/build.gradle b/protobuf/build.gradle index b4204bd6311..384bd3e2fba 100644 --- a/protobuf/build.gradle +++ b/protobuf/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.google.protobuf" } diff --git a/services/build.gradle b/services/build.gradle index 739b2d9f279..cac01f3d9ad 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.google.protobuf" } diff --git a/stub/build.gradle b/stub/build.gradle index 3ee264db4be..6e9264b087e 100644 --- a/stub/build.gradle +++ b/stub/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "maven-publish" +} + description = "gRPC: Stub" dependencies { compile project(':grpc-api') diff --git a/testing-proto/build.gradle b/testing-proto/build.gradle index 6a09b2f7783..25a717bf3ff 100644 --- a/testing-proto/build.gradle +++ b/testing-proto/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.google.protobuf" } diff --git a/testing/build.gradle b/testing/build.gradle index fa038fc4569..450377072f8 100644 --- a/testing/build.gradle +++ b/testing/build.gradle @@ -1,3 +1,7 @@ +plugins { + id "maven-publish" +} + description = "gRPC: Testing" dependencies { diff --git a/xds/build.gradle b/xds/build.gradle index 9aaadcff7c2..fb98b48cd0d 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -1,4 +1,6 @@ plugins { + id "maven-publish" + id "com.github.johnrengelman.shadow" id "com.google.protobuf" } @@ -68,3 +70,4 @@ publishing { } } } +[publishMavenPublicationToMavenRepository, publishMavenPublicationToMavenLocal]*.onlyIf { false } From 3b29f7427160a173a770294a5e7825847d922fd2 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 09:38:17 -0700 Subject: [PATCH 010/131] Move ALPN Agent configuration to each project needing it --- benchmarks/build.gradle | 5 +++++ build.gradle | 5 ----- interop-testing/build.gradle | 5 +++++ netty/build.gradle | 6 ++++++ 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index a31d55b2d31..a91c7b26e10 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -18,6 +18,10 @@ jmh { includeTests = true } +configurations { + alpnagent +} + dependencies { compile project(':grpc-core'), project(':grpc-netty'), @@ -32,6 +36,7 @@ dependencies { libraries.netty_epoll, libraries.math compileOnly libraries.javax_annotation + alpnagent libraries.jetty_alpn_agent } import net.ltgt.gradle.errorprone.CheckSeverity diff --git a/build.gradle b/build.gradle index 5360313afd3..dbc0da1ee08 100644 --- a/build.gradle +++ b/build.gradle @@ -220,8 +220,6 @@ subprojects { // Define a separate configuration for managing the dependency on Jetty ALPN agent. configurations { - alpnagent - compile { // Detect Maven Enforcer's dependencyConvergence failures. We only // care for artifacts used as libraries by others. @@ -239,9 +237,6 @@ subprojects { testCompile libraries.junit, libraries.mockito, libraries.truth - - // Configuration for modules that use Jetty ALPN agent - alpnagent libraries.jetty_alpn_agent } // Disable JavaDoc doclint on Java 8. It's annoying. diff --git a/interop-testing/build.gradle b/interop-testing/build.gradle index a1709c1964e..2178705c439 100644 --- a/interop-testing/build.gradle +++ b/interop-testing/build.gradle @@ -8,6 +8,10 @@ plugins { description = "gRPC: Integration Testing" startScripts.enabled = false +configurations { + alpnagent +} + dependencies { compile project(':grpc-alts'), project(':grpc-auth'), @@ -26,6 +30,7 @@ dependencies { project(':grpc-grpclb') testCompile project(':grpc-context').sourceSets.test.output, libraries.mockito + alpnagent libraries.jetty_alpn_agent } configureProtoCompilation() diff --git a/netty/build.gradle b/netty/build.gradle index 60b7d8a750f..2143c3cd473 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -5,6 +5,11 @@ plugins { } description = "gRPC: Netty" + +configurations { + alpnagent +} + dependencies { compile project(':grpc-core'), libraries.netty, @@ -18,6 +23,7 @@ dependencies { libraries.conscrypt, libraries.netty_epoll signature "org.codehaus.mojo.signature:java17:1.0@signature" + alpnagent libraries.jetty_alpn_agent } import net.ltgt.gradle.errorprone.CheckSeverity From e13221b5035aa4727ebb173ac0e1def73d07bff7 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 10:23:23 -0700 Subject: [PATCH 011/131] Apply japicmp plugin explicitly when needed --- auth/build.gradle | 2 ++ build.gradle | 26 +++----------------------- context/build.gradle | 1 + core/build.gradle | 1 + grpclb/build.gradle | 1 + netty/build.gradle | 1 + okhttp/build.gradle | 2 ++ protobuf-lite/build.gradle | 1 + protobuf/build.gradle | 1 + stub/build.gradle | 2 ++ testing/build.gradle | 2 ++ 11 files changed, 17 insertions(+), 23 deletions(-) diff --git a/auth/build.gradle b/auth/build.gradle index 85509f51dfc..a95d141962b 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -1,5 +1,7 @@ plugins { id "maven-publish" + + id "me.champeau.gradle.japicmp" } description = "gRPC: Auth" diff --git a/build.gradle b/build.gradle index dbc0da1ee08..7591959fd73 100644 --- a/build.gradle +++ b/build.gradle @@ -413,30 +413,10 @@ subprojects { } maxHeapSize = '1500m' } -} -// Run with: ./gradlew japicmp --continue -def baselineGrpcVersion = '1.6.1' -def publicApiSubprojects = [ - // TODO: uncomment after grpc-alts, grpc-bom artifact is published. - // ':grpc-alts', - //':grpc-api', - ':grpc-auth', - //':grpc-bom', - ':grpc-context', - ':grpc-core', - ':grpc-grpclb', - ':grpc-netty', - ':grpc-okhttp', - ':grpc-protobuf', - ':grpc-protobuf-lite', - ':grpc-stub', - ':grpc-testing', -] - -publicApiSubprojects.each { name -> - project(":$name") { - apply plugin: 'me.champeau.gradle.japicmp' + // Run with: ./gradlew japicmp --continue + plugins.withId("me.champeau.gradle.japicmp") { + def baselineGrpcVersion = '1.6.1' // Get the baseline version's jar for this subproject File baselineArtifact = null diff --git a/context/build.gradle b/context/build.gradle index b2c3c4d5a18..dbde77aa2c9 100644 --- a/context/build.gradle +++ b/context/build.gradle @@ -1,6 +1,7 @@ plugins { id "maven-publish" + id "me.champeau.gradle.japicmp" id "me.champeau.gradle.jmh" } diff --git a/core/build.gradle b/core/build.gradle index f9b81a0a977..4e0ef7dee08 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,6 +1,7 @@ plugins { id "maven-publish" + id "me.champeau.gradle.japicmp" id "me.champeau.gradle.jmh" } diff --git a/grpclb/build.gradle b/grpclb/build.gradle index 7488fd0b52b..c044e72091d 100644 --- a/grpclb/build.gradle +++ b/grpclb/build.gradle @@ -2,6 +2,7 @@ plugins { id "maven-publish" id "com.google.protobuf" + id "me.champeau.gradle.japicmp" } description = "gRPC: GRPCLB LoadBalancer plugin" diff --git a/netty/build.gradle b/netty/build.gradle index 2143c3cd473..9076c7f0ac5 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -1,6 +1,7 @@ plugins { id "maven-publish" + id "me.champeau.gradle.japicmp" id "me.champeau.gradle.jmh" } diff --git a/okhttp/build.gradle b/okhttp/build.gradle index 5b6fd6d4689..c88bf262a3b 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -1,5 +1,7 @@ plugins { id "maven-publish" + + id "me.champeau.gradle.japicmp" } description = "gRPC: OkHttp" diff --git a/protobuf-lite/build.gradle b/protobuf-lite/build.gradle index 49d42570c0e..217f08795b6 100644 --- a/protobuf-lite/build.gradle +++ b/protobuf-lite/build.gradle @@ -2,6 +2,7 @@ plugins { id "maven-publish" id "com.google.protobuf" + id "me.champeau.gradle.japicmp" } description = 'gRPC: Protobuf Lite' diff --git a/protobuf/build.gradle b/protobuf/build.gradle index 384bd3e2fba..fb1ca70c54d 100644 --- a/protobuf/build.gradle +++ b/protobuf/build.gradle @@ -2,6 +2,7 @@ plugins { id "maven-publish" id "com.google.protobuf" + id "me.champeau.gradle.japicmp" } description = 'gRPC: Protobuf' diff --git a/stub/build.gradle b/stub/build.gradle index 6e9264b087e..8a4e1e357cc 100644 --- a/stub/build.gradle +++ b/stub/build.gradle @@ -1,5 +1,7 @@ plugins { id "maven-publish" + + id "me.champeau.gradle.japicmp" } description = "gRPC: Stub" diff --git a/testing/build.gradle b/testing/build.gradle index 450377072f8..c156c7b45e9 100644 --- a/testing/build.gradle +++ b/testing/build.gradle @@ -1,5 +1,7 @@ plugins { id "maven-publish" + + id "me.champeau.gradle.japicmp" } description = "gRPC: Testing" From 4215b80b816e78bdbb5c78ad43de9d26381aeef5 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 10:24:29 -0700 Subject: [PATCH 012/131] Apply java plugin explicitly when needed --- all/build.gradle | 1 + alts/build.gradle | 1 + api/build.gradle | 1 + auth/build.gradle | 1 + benchmarks/build.gradle | 1 + build.gradle | 181 +++++++++++++++++++---------------- compiler/build.gradle | 1 + context/build.gradle | 1 + core/build.gradle | 4 + grpclb/build.gradle | 3 + interop-testing/build.gradle | 1 + netty/build.gradle | 1 + netty/shaded/build.gradle | 1 + okhttp/build.gradle | 1 + protobuf-lite/build.gradle | 1 + protobuf/build.gradle | 1 + services/build.gradle | 1 + stub/build.gradle | 1 + testing-proto/build.gradle | 1 + testing/build.gradle | 1 + xds/build.gradle | 1 + 21 files changed, 122 insertions(+), 84 deletions(-) diff --git a/all/build.gradle b/all/build.gradle index 5cd86feb47e..060a8d0ae21 100644 --- a/all/build.gradle +++ b/all/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.github.kt3k.coveralls" diff --git a/alts/build.gradle b/alts/build.gradle index 4b06db9e5d3..3d510205bb5 100644 --- a/alts/build.gradle +++ b/alts/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.github.johnrengelman.shadow" diff --git a/api/build.gradle b/api/build.gradle index ce4662904c3..aecda524424 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.jmh" diff --git a/auth/build.gradle b/auth/build.gradle index a95d141962b..808766a23ce 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index a91c7b26e10..7aef7870e3f 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -1,5 +1,6 @@ plugins { id "application" + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/build.gradle b/build.gradle index 7591959fd73..7c41ffd6443 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,6 @@ import net.ltgt.gradle.errorprone.CheckSeverity subprojects { apply plugin: "checkstyle" - apply plugin: "java" apply plugin: "maven" apply plugin: "idea" apply plugin: "signing" @@ -20,30 +19,10 @@ subprojects { apply plugin: "ru.vyarus.animalsniffer" apply plugin: "net.ltgt.errorprone" - if (rootProject.properties.get('errorProne', true)) { - dependencies { - errorprone 'com.google.errorprone:error_prone_core:2.3.3' - errorproneJavac 'com.google.errorprone:javac:9+181-r4173-1' - - annotationProcessor 'com.google.guava:guava-beta-checker:1.0' - } - } else { - // Disable Error Prone - allprojects { - afterEvaluate { project -> - project.tasks.withType(JavaCompile) { - options.errorprone.enabled = false - } - } - } - } group = "io.grpc" version = "1.25.0-SNAPSHOT" // CURRENT_GRPC_VERSION - sourceCompatibility = 1.7 - targetCompatibility = 1.7 - repositories { maven { // The google mirror is less flaky than mavenCentral() url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } @@ -63,31 +42,6 @@ subprojects { } } - compileTestJava { - // serialVersionUID is basically guaranteed to be useless in our tests - options.compilerArgs += [ - "-Xlint:-serial" - ] - // LinkedList doesn't hurt much in tests and has lots of usages - options.errorprone.check("JdkObsolete", CheckSeverity.OFF) - } - - jar.manifest { - attributes('Implementation-Title': name, - 'Implementation-Version': version, - 'Built-By': System.getProperty('user.name'), - 'Built-JDK': System.getProperty('java.version'), - 'Source-Compatibility': sourceCompatibility, - 'Target-Compatibility': targetCompatibility) - } - - javadoc.options { - encoding = 'UTF-8' - use = true - links 'https://docs.oracle.com/javase/8/docs/api/' - source = "8" - } - ext { def exeSuffix = osdetector.os == 'windows' ? ".exe" : "" protocPluginBaseName = 'protoc-gen-grpc-java' @@ -233,12 +187,6 @@ subprojects { } } - dependencies { - testCompile libraries.junit, - libraries.mockito, - libraries.truth - } - // Disable JavaDoc doclint on Java 8. It's annoying. if (JavaVersion.current().isJava8Compatible()) { allprojects { @@ -268,12 +216,81 @@ subprojects { } } - checkstyleMain { - source = fileTree(dir: "src/main", include: "**/*.java") - } + plugins.withId("java") { + sourceCompatibility = 1.7 + targetCompatibility = 1.7 + + dependencies { + testCompile libraries.junit, + libraries.mockito, + libraries.truth + } + + compileTestJava { + // serialVersionUID is basically guaranteed to be useless in our tests + options.compilerArgs += [ + "-Xlint:-serial" + ] + } + + jar.manifest { + attributes('Implementation-Title': name, + 'Implementation-Version': version, + 'Built-By': System.getProperty('user.name'), + 'Built-JDK': System.getProperty('java.version'), + 'Source-Compatibility': sourceCompatibility, + 'Target-Compatibility': targetCompatibility) + } + + javadoc.options { + encoding = 'UTF-8' + use = true + links 'https://docs.oracle.com/javase/8/docs/api/' + source = "8" + } + + checkstyleMain { + source = fileTree(dir: "src/main", include: "**/*.java") + } - checkstyleTest { - source = fileTree(dir: "src/test", include: "**/*.java") + checkstyleTest { + source = fileTree(dir: "src/test", include: "**/*.java") + } + + // At a test failure, log the stack trace to the console so that we don't + // have to open the HTML in a browser. + test { + testLogging { + exceptionFormat = 'full' + showExceptions true + showCauses true + showStackTraces true + } + maxHeapSize = '1500m' + } + + if (rootProject.properties.get('errorProne', true)) { + dependencies { + errorprone 'com.google.errorprone:error_prone_core:2.3.3' + errorproneJavac 'com.google.errorprone:javac:9+181-r4173-1' + + annotationProcessor 'com.google.guava:guava-beta-checker:1.0' + } + } else { + // Disable Error Prone + allprojects { + afterEvaluate { project -> + project.tasks.withType(JavaCompile) { + options.errorprone.enabled = false + } + } + } + } + + compileTestJava { + // LinkedList doesn't hurt much in tests and has lots of usages + options.errorprone.check("JdkObsolete", CheckSeverity.OFF) + } } plugins.withId("me.champeau.gradle.jmh") { @@ -300,27 +317,10 @@ subprojects { } plugins.withId("maven-publish") { - task javadocJar(type: Jar) { - classifier = 'javadoc' - from javadoc - } - - task sourcesJar(type: Jar) { - classifier = 'sources' - from sourceSets.main.allSource - } - publishing { publications { // do not use mavenJava, as java plugin will modify it via "magic" maven(MavenPublication) { - if (project.name != 'grpc-netty-shaded') { - from components.java - } - - artifact javadocJar - artifact sourcesJar - pom { name = project.group + ":" + project.name url = 'https://github.com/grpc/grpc-java' @@ -400,18 +400,31 @@ subprojects { required false sign publishing.publications.maven } - } - // At a test failure, log the stack trace to the console so that we don't - // have to open the HTML in a browser. - test { - testLogging { - exceptionFormat = 'full' - showExceptions true - showCauses true - showStackTraces true + plugins.withId("java") { + task javadocJar(type: Jar) { + classifier = 'javadoc' + from javadoc + } + + task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allSource + } + + publishing { + publications { + maven { + if (project.name != 'grpc-netty-shaded') { + from components.java + } + + artifact javadocJar + artifact sourcesJar + } + } + } } - maxHeapSize = '1500m' } // Run with: ./gradlew japicmp --continue diff --git a/compiler/build.gradle b/compiler/build.gradle index 1b0a21037fb..ad2a609b6e4 100644 --- a/compiler/build.gradle +++ b/compiler/build.gradle @@ -1,5 +1,6 @@ plugins { id "cpp" + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/context/build.gradle b/context/build.gradle index dbde77aa2c9..6903bcf03a4 100644 --- a/context/build.gradle +++ b/context/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" diff --git a/core/build.gradle b/core/build.gradle index 4e0ef7dee08..2f734ca5270 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" @@ -7,6 +8,9 @@ plugins { description = 'gRPC: Core' +evaluationDependsOn(project(':grpc-context').path) +evaluationDependsOn(project(':grpc-api').path) + dependencies { compile project(':grpc-api'), libraries.gson, diff --git a/grpclb/build.gradle b/grpclb/build.gradle index c044e72091d..bf5a9ca906c 100644 --- a/grpclb/build.gradle +++ b/grpclb/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.google.protobuf" @@ -7,6 +8,8 @@ plugins { description = "gRPC: GRPCLB LoadBalancer plugin" +evaluationDependsOn(project(':grpc-core').path) + dependencies { compile project(':grpc-core'), project(':grpc-protobuf'), diff --git a/interop-testing/build.gradle b/interop-testing/build.gradle index 2178705c439..369dcc11f4b 100644 --- a/interop-testing/build.gradle +++ b/interop-testing/build.gradle @@ -1,5 +1,6 @@ plugins { id "application" + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/netty/build.gradle b/netty/build.gradle index 9076c7f0ac5..374504e14bf 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" diff --git a/netty/shaded/build.gradle b/netty/shaded/build.gradle index 609e6c3c28d..1ecc36d9708 100644 --- a/netty/shaded/build.gradle +++ b/netty/shaded/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.github.johnrengelman.shadow" diff --git a/okhttp/build.gradle b/okhttp/build.gradle index c88bf262a3b..1cf98513a05 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" diff --git a/protobuf-lite/build.gradle b/protobuf-lite/build.gradle index 217f08795b6..9bbe1085292 100644 --- a/protobuf-lite/build.gradle +++ b/protobuf-lite/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/protobuf/build.gradle b/protobuf/build.gradle index fb1ca70c54d..45e0c637cc6 100644 --- a/protobuf/build.gradle +++ b/protobuf/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/services/build.gradle b/services/build.gradle index cac01f3d9ad..03f7a6de75a 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/stub/build.gradle b/stub/build.gradle index 8a4e1e357cc..24df11721b6 100644 --- a/stub/build.gradle +++ b/stub/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" diff --git a/testing-proto/build.gradle b/testing-proto/build.gradle index 25a717bf3ff..8ff8ccc6c0e 100644 --- a/testing-proto/build.gradle +++ b/testing-proto/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.google.protobuf" diff --git a/testing/build.gradle b/testing/build.gradle index c156c7b45e9..e64611d9eb1 100644 --- a/testing/build.gradle +++ b/testing/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "me.champeau.gradle.japicmp" diff --git a/xds/build.gradle b/xds/build.gradle index fb98b48cd0d..7a111e88392 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -1,4 +1,5 @@ plugins { + id "java" id "maven-publish" id "com.github.johnrengelman.shadow" From 2b945774b61c3fc7b9911e993f88e9cee2a25eb2 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Sat, 7 Sep 2019 10:38:58 -0700 Subject: [PATCH 013/131] Apply animalsniffer plugin explicitly when needed --- alts/build.gradle | 1 + api/build.gradle | 1 + auth/build.gradle | 1 + build.gradle | 4 ---- context/build.gradle | 1 + core/build.gradle | 1 + netty/build.gradle | 1 + okhttp/build.gradle | 1 + protobuf-lite/build.gradle | 1 + protobuf/build.gradle | 1 + services/build.gradle | 1 + stub/build.gradle | 1 + xds/build.gradle | 1 + 13 files changed, 12 insertions(+), 4 deletions(-) diff --git a/alts/build.gradle b/alts/build.gradle index 3d510205bb5..79db7949614 100644 --- a/alts/build.gradle +++ b/alts/build.gradle @@ -4,6 +4,7 @@ plugins { id "com.github.johnrengelman.shadow" id "com.google.protobuf" + id "ru.vyarus.animalsniffer" } description = "gRPC: ALTS" diff --git a/api/build.gradle b/api/build.gradle index aecda524424..6703deaf390 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -3,6 +3,7 @@ plugins { id "maven-publish" id "me.champeau.gradle.jmh" + id "ru.vyarus.animalsniffer" } description = 'gRPC: API' diff --git a/auth/build.gradle b/auth/build.gradle index 808766a23ce..2dafc0f4fd9 100644 --- a/auth/build.gradle +++ b/auth/build.gradle @@ -3,6 +3,7 @@ plugins { id "maven-publish" id "me.champeau.gradle.japicmp" + id "ru.vyarus.animalsniffer" } description = "gRPC: Auth" diff --git a/build.gradle b/build.gradle index 7c41ffd6443..410ce317540 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,6 @@ plugins { id "com.google.osdetector" apply false id "me.champeau.gradle.japicmp" apply false id "net.ltgt.errorprone" apply false - id "ru.vyarus.animalsniffer" apply false } import net.ltgt.gradle.errorprone.CheckSeverity @@ -15,9 +14,6 @@ subprojects { apply plugin: "jacoco" apply plugin: "com.google.osdetector" - // The plugin only has an effect if a signature is specified - apply plugin: "ru.vyarus.animalsniffer" - apply plugin: "net.ltgt.errorprone" group = "io.grpc" diff --git a/context/build.gradle b/context/build.gradle index 6903bcf03a4..832e22accba 100644 --- a/context/build.gradle +++ b/context/build.gradle @@ -4,6 +4,7 @@ plugins { id "me.champeau.gradle.japicmp" id "me.champeau.gradle.jmh" + id "ru.vyarus.animalsniffer" } description = 'gRPC: Context' diff --git a/core/build.gradle b/core/build.gradle index 2f734ca5270..2b0f2c6cf6a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -4,6 +4,7 @@ plugins { id "me.champeau.gradle.japicmp" id "me.champeau.gradle.jmh" + id "ru.vyarus.animalsniffer" } description = 'gRPC: Core' diff --git a/netty/build.gradle b/netty/build.gradle index 374504e14bf..ad573eaaca7 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -4,6 +4,7 @@ plugins { id "me.champeau.gradle.japicmp" id "me.champeau.gradle.jmh" + id "ru.vyarus.animalsniffer" } description = "gRPC: Netty" diff --git a/okhttp/build.gradle b/okhttp/build.gradle index 1cf98513a05..205a6601ae7 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -3,6 +3,7 @@ plugins { id "maven-publish" id "me.champeau.gradle.japicmp" + id "ru.vyarus.animalsniffer" } description = "gRPC: OkHttp" diff --git a/protobuf-lite/build.gradle b/protobuf-lite/build.gradle index 9bbe1085292..a470c2da7c3 100644 --- a/protobuf-lite/build.gradle +++ b/protobuf-lite/build.gradle @@ -4,6 +4,7 @@ plugins { id "com.google.protobuf" id "me.champeau.gradle.japicmp" + id "ru.vyarus.animalsniffer" } description = 'gRPC: Protobuf Lite' diff --git a/protobuf/build.gradle b/protobuf/build.gradle index 45e0c637cc6..04221aa7eb0 100644 --- a/protobuf/build.gradle +++ b/protobuf/build.gradle @@ -4,6 +4,7 @@ plugins { id "com.google.protobuf" id "me.champeau.gradle.japicmp" + id "ru.vyarus.animalsniffer" } description = 'gRPC: Protobuf' diff --git a/services/build.gradle b/services/build.gradle index 03f7a6de75a..d55b261cbce 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -3,6 +3,7 @@ plugins { id "maven-publish" id "com.google.protobuf" + id "ru.vyarus.animalsniffer" } description = "gRPC: Services" diff --git a/stub/build.gradle b/stub/build.gradle index 24df11721b6..2b7c82e5bfc 100644 --- a/stub/build.gradle +++ b/stub/build.gradle @@ -3,6 +3,7 @@ plugins { id "maven-publish" id "me.champeau.gradle.japicmp" + id "ru.vyarus.animalsniffer" } description = "gRPC: Stub" diff --git a/xds/build.gradle b/xds/build.gradle index 7a111e88392..dd06273326f 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -4,6 +4,7 @@ plugins { id "com.github.johnrengelman.shadow" id "com.google.protobuf" + id "ru.vyarus.animalsniffer" } description = "gRPC: XDS plugin" From 858a1f8fb9fb4dedc93a2a60bf8afcebd48c08ea Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Fri, 13 Sep 2019 14:16:08 -0400 Subject: [PATCH 014/131] Update to Guava 28.1 Remove serviceAccountWithScopeNotToJwt as test no longer makes sense and it is hard to adapt to the new cred API. --- .../GoogleAuthLibraryCallCredentialsTest.java | 48 ++++++------------- build.gradle | 4 +- repositories.bzl | 16 +++---- 3 files changed, 24 insertions(+), 44 deletions(-) diff --git a/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java b/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java index bb1a569abf9..b34451bcf94 100644 --- a/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java +++ b/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java @@ -30,6 +30,7 @@ import com.google.auth.Credentials; import com.google.auth.RequestMetadataCallback; +import com.google.auth.http.HttpTransportFactory; import com.google.auth.oauth2.AccessToken; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.OAuth2Credentials; @@ -67,6 +68,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.Captor; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -252,7 +254,7 @@ public void credentialsReturnNullMetadata() throws Exception { @Test public void oauth2Credential() { final AccessToken token = new AccessToken("allyourbase", new Date(Long.MAX_VALUE)); - final OAuth2Credentials credentials = new OAuth2Credentials() { + OAuth2Credentials credentials = new OAuth2Credentials() { @Override public AccessToken refreshAccessToken() throws IOException { return token; @@ -323,14 +325,17 @@ public void serviceUri() throws Exception { @Test public void serviceAccountToJwt() throws Exception { KeyPair pair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); - @SuppressWarnings("deprecation") - ServiceAccountCredentials credentials = new ServiceAccountCredentials( - null, "email@example.com", pair.getPrivate(), null, null) { - @Override - public AccessToken refreshAccessToken() { - throw new AssertionError(); - } - }; + + HttpTransportFactory factory = Mockito.mock(HttpTransportFactory.class); + Mockito.when(factory.create()).thenThrow(new AssertionError()); + + ServiceAccountCredentials credentials = + ServiceAccountCredentials.newBuilder() + .setClientEmail("test-email@example.com") + .setPrivateKey(pair.getPrivate()) + .setPrivateKeyId("test-private-key-id") + .setHttpTransportFactory(factory) + .build(); GoogleAuthLibraryCallCredentials callCredentials = new GoogleAuthLibraryCallCredentials(credentials); @@ -346,31 +351,6 @@ public AccessToken refreshAccessToken() { assertTrue(authorization[0], authorization[0].length() > 300); } - @Test - public void serviceAccountWithScopeNotToJwt() throws Exception { - final AccessToken token = new AccessToken("allyourbase", new Date(Long.MAX_VALUE)); - KeyPair pair = KeyPairGenerator.getInstance("RSA").generateKeyPair(); - @SuppressWarnings("deprecation") - ServiceAccountCredentials credentials = new ServiceAccountCredentials( - null, "email@example.com", pair.getPrivate(), null, Arrays.asList("somescope")) { - @Override - public AccessToken refreshAccessToken() { - return token; - } - }; - - GoogleAuthLibraryCallCredentials callCredentials = - new GoogleAuthLibraryCallCredentials(credentials); - callCredentials.applyRequestMetadata(new RequestInfoImpl(), executor, applier); - assertEquals(1, runPendingRunnables()); - - verify(applier).apply(headersCaptor.capture()); - Metadata headers = headersCaptor.getValue(); - Iterable authorization = headers.getAll(AUTHORIZATION); - assertArrayEquals(new String[]{"Bearer allyourbase"}, - Iterables.toArray(authorization, String.class)); - } - @Test public void oauthClassesNotInClassPath() throws Exception { ListMultimap values = LinkedListMultimap.create(); diff --git a/build.gradle b/build.gradle index 410ce317540..884c5250c15 100644 --- a/build.gradle +++ b/build.gradle @@ -44,8 +44,8 @@ subprojects { javaPluginPath = "$rootDir/compiler/build/exe/java_plugin/$protocPluginBaseName$exeSuffix" nettyVersion = '4.1.38.Final' - googleauthVersion = '0.13.0' - guavaVersion = '26.0-android' + guavaVersion = '28.1-android' + googleauthVersion = '0.17.1' protobufVersion = '3.9.0' protocVersion = protobufVersion opencensusVersion = '0.21.0' diff --git a/repositories.bzl b/repositories.bzl index 66ed0b9ac53..82f7a59a77c 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -196,18 +196,18 @@ def com_google_api_grpc_google_common_protos(): def com_google_auth_google_auth_library_credentials(): jvm_maven_import_external( name = "com_google_auth_google_auth_library_credentials", - artifact = "com.google.auth:google-auth-library-credentials:0.9.0", + artifact = "com.google.auth:google-auth-library-credentials:0.17.1", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "ac9efdd6a930e4df906fa278576fa825d979f74315f2faf5c91fe7e6aabb2788", + artifact_sha256 = "aaeea9333fff9b763715bca0174ec76c4f9551b5731c89a95f263cdc82b4b56e", licenses = ["notice"], # BSD 3-clause ) def com_google_auth_google_auth_library_oauth2_http(): jvm_maven_import_external( name = "com_google_auth_google_auth_library_oauth2_http", - artifact = "com.google.auth:google-auth-library-oauth2-http:0.9.0", + artifact = "com.google.auth:google-auth-library-oauth2-http:0.17.1", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "e55d9722102cc1245c8c43d69acd49d3c9bbfcc1bcf722e971425506b970097e", + artifact_sha256 = "fa9a1589c8bc279416988d437c2636967cd5e4eff70fbddc986b9c5a77b0231b", licenses = ["notice"], # BSD 3-clause ) @@ -241,9 +241,9 @@ def com_google_errorprone_error_prone_annotations(): def com_google_guava(): jvm_maven_import_external( name = "com_google_guava_guava", - artifact = "com.google.guava:guava:26.0-android", + artifact = "com.google.guava:guava:28.1-android", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "1d044ebb866ef08b7d04e998b4260c9b52fab6e6d6b68d207859486bb3686cd5", + artifact_sha256 = "e112ce92c0f0733965eede73d94589c59a72128b06b08bba5ebe2f9ea672ef60", licenses = ["notice"], # Apache 2.0 ) @@ -260,9 +260,9 @@ def com_google_guava_failureaccess(): def com_google_j2objc_j2objc_annotations(): jvm_maven_import_external( name = "com_google_j2objc_j2objc_annotations", - artifact = "com.google.j2objc:j2objc-annotations:1.1", + artifact = "com.google.j2objc:j2objc-annotations:1.3", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6", + artifact_sha256 = "21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b", licenses = ["notice"], # Apache 2.0 ) From 433458368129a46af0fa0315fdcf14331c210fc9 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Fri, 13 Sep 2019 12:11:27 -0700 Subject: [PATCH 015/131] xds: restructure XdsLoadBalancer part 1 - Get rid of `XdsLbState` and make config change handling into two layers: `LookasideLb` (handles balancer name) and `LookasideChannelLb` (handles child policy), under `XdsLoadBalanecer` (fallback manager layer) - Move `XdsComms`/`AdsStream` to a layer under `LookasideChannelLb`. They don't keep the helper, but only `SyncCtx` and `ChannelLogger` - For each layer, we pass in a `LoadBalancer.Factory` for the next/child layer. In test, + we mock/fake the factory, so we don't care about the implementation details of the child layer. + we capture the helper of `factory.newBalancer(factory)`, so we can mimic `updateBalancingState() `from the child layer. Part 1 contains fallback management logic. There is no change in fallback management logic. --- .../java/io/grpc/xds/XdsLoadBalancer2.java | 248 +++++++++++++++ .../io/grpc/xds/XdsLoadBalancer2Test.java | 297 ++++++++++++++++++ 2 files changed, 545 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java create mode 100644 xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java diff --git a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java new file mode 100644 index 00000000000..11df68f39fd --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java @@ -0,0 +1,248 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.annotations.VisibleForTesting; +import io.grpc.ChannelLogger.ChannelLogLevel; +import io.grpc.ConnectivityState; +import io.grpc.ConnectivityStateInfo; +import io.grpc.LoadBalancer; +import io.grpc.Status; +import io.grpc.SynchronizationContext.ScheduledHandle; +import io.grpc.util.ForwardingLoadBalancerHelper; +import io.grpc.xds.XdsComms.AdsStreamCallback; +import java.util.concurrent.TimeUnit; +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +/** + * A {@link LoadBalancer} that uses the XDS protocol. + * + *

This class manages fallback handling. The logic for child policy handling and fallback policy + * handling is provided by LookasideLb and FallbackLb. + */ +// TODO(zdapeng): migrate name to XdsLoadBlancer +final class XdsLoadBalancer2 extends LoadBalancer { + + private static final long FALLBACK_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); // same as grpclb + + private final Helper helper; + private final LoadBalancer lookasideLb; + private final LoadBalancer.Factory fallbackLbFactory; + private final AdsStreamCallback adsCallback = new AdsStreamCallback() { + @Override + public void onWorking() { + if (childPolicyHasBeenReady) { + // cancel Fallback-After-Startup timer if there's any + cancelFallbackTimer(); + } + + adsWorked = true; + } + + @Override + public void onError() { + if (!adsWorked) { + // start Fallback-at-Startup immediately + useFallbackPolicy(); + } else if (childPolicyHasBeenReady) { + // TODO: schedule a timer for Fallback-After-Startup + } // else: the Fallback-at-Startup timer is still pending, noop and wait + } + + @Override + public void onAllDrop() { + cancelFallback(); + } + }; + + @Nullable + private LoadBalancer fallbackLb; + @Nullable + private ResolvedAddresses resolvedAddresses; + // Scheduled only once. Never reset to null. + @CheckForNull + private ScheduledHandle fallbackTimer; + private boolean adsWorked; + private boolean childPolicyHasBeenReady; + + // TODO(zdapeng): Add XdsLoadBalancer2(Helper helper) with default factories + @VisibleForTesting + XdsLoadBalancer2( + Helper helper, + LookasideLbFactory lookasideLbFactory, + LoadBalancer.Factory fallbackLbFactory) { + this.helper = helper; + this.lookasideLb = lookasideLbFactory.newLoadBalancer(new LookasideLbHelper(), adsCallback); + this.fallbackLbFactory = fallbackLbFactory; + } + + @Override + public boolean canHandleEmptyAddressListFromNameResolution() { + // This does not sound correct, but it's fine as we don't support fallback at this moment. + // TODO(zdapeng): revisit it once we officially support fallback. + return true; + } + + @Override + public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { + this.resolvedAddresses = resolvedAddresses; + + if (isInFallbackMode()) { + fallbackLb.handleResolvedAddresses(this.resolvedAddresses); + } + + if (fallbackTimer == null) { + class EnterFallbackTask implements Runnable { + + @Override + public void run() { + useFallbackPolicy(); + } + } + + fallbackTimer = helper.getSynchronizationContext().schedule( + new EnterFallbackTask(), FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS, + helper.getScheduledExecutorService()); + } + + lookasideLb.handleResolvedAddresses(resolvedAddresses); + } + + @Override + public void handleNameResolutionError(Status error) { + lookasideLb.handleNameResolutionError(error); + if (isInFallbackMode()) { + fallbackLb.handleNameResolutionError(error); + } + } + + @Override + public void requestConnection() { + lookasideLb.requestConnection(); + if (isInFallbackMode()) { + fallbackLb.requestConnection(); + } + } + + @Override + public void shutdown() { + helper.getChannelLogger().log( + ChannelLogLevel.INFO, "Shutting down XDS balancer"); + lookasideLb.shutdown(); + cancelFallback(); + } + + @Deprecated + public void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo stateInfo) { + throw new UnsupportedOperationException( + "handleSubchannelState() not supported by XdsLoadBalancer"); + } + + private void cancelFallbackTimer() { + if (fallbackTimer != null) { + fallbackTimer.cancel(); + } + } + + private void cancelFallback() { + cancelFallbackTimer(); + if (isInFallbackMode()) { + helper.getChannelLogger().log( + ChannelLogLevel.INFO, "Shutting down XDS fallback balancer"); + fallbackLb.shutdown(); + fallbackLb = null; + } + } + + private void useFallbackPolicy() { + if (isInFallbackMode()) { + return; + } + cancelFallbackTimer(); + helper.getChannelLogger().log( + ChannelLogLevel.INFO, "Using XDS fallback policy"); + + FallbackLbHelper fallbackLbHelper = new FallbackLbHelper(); + fallbackLb = fallbackLbFactory.newLoadBalancer(fallbackLbHelper); + fallbackLbHelper.balancer = fallbackLb; + fallbackLb.handleResolvedAddresses(resolvedAddresses); + } + + /** + * Fallback mode being on indicates that an update from child LBs will be ignored unless the + * update triggers turning off the fallback mode first. + */ + private boolean isInFallbackMode() { + return fallbackLb != null; + } + + private final class LookasideLbHelper extends ForwardingLoadBalancerHelper { + + @Override + protected Helper delegate() { + return helper; + } + + @Override + public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { + if (newState == ConnectivityState.READY) { + checkState( + adsWorked, + "channel goes to READY before the load balancer even worked"); + childPolicyHasBeenReady = true; + cancelFallback(); + } + if (!isInFallbackMode()) { + helper.getChannelLogger().log( + ChannelLogLevel.INFO, "Picker updated - state: {0}, picker: {1}", newState, newPicker); + helper.updateBalancingState(newState, newPicker); + } + } + } + + private final class FallbackLbHelper extends ForwardingLoadBalancerHelper { + LoadBalancer balancer; + + @Override + protected Helper delegate() { + return helper; + } + + @Override + public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { + checkNotNull(balancer, "balancer not set yet"); + if (balancer != fallbackLb) { + // ignore updates from a misbehaving shutdown fallback balancer + return; + } + helper.getChannelLogger().log( + ChannelLogLevel.INFO, + "Picker updated - state: {0}, picker: {1}", newState, newPicker); + super.updateBalancingState(newState, newPicker); + } + } + + /** Factory of a look-aside load balancer. The interface itself is for convenience in test. */ + @VisibleForTesting + interface LookasideLbFactory { + LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback); + } +} diff --git a/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java new file mode 100644 index 00000000000..f52d17844f1 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java @@ -0,0 +1,297 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.truth.Truth.assertThat; +import static io.grpc.ConnectivityState.CONNECTING; +import static io.grpc.ConnectivityState.READY; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import io.grpc.Attributes; +import io.grpc.ChannelLogger; +import io.grpc.ConnectivityStateInfo; +import io.grpc.EquivalentAddressGroup; +import io.grpc.LoadBalancer; +import io.grpc.LoadBalancer.Helper; +import io.grpc.LoadBalancer.ResolvedAddresses; +import io.grpc.LoadBalancer.Subchannel; +import io.grpc.LoadBalancer.SubchannelPicker; +import io.grpc.Status; +import io.grpc.SynchronizationContext; +import io.grpc.internal.FakeClock; +import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.XdsLoadBalancer2.LookasideLbFactory; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Unit tests for {@link XdsLoadBalancer2}. */ +@RunWith(JUnit4.class) +public class XdsLoadBalancer2Test { + @Rule + public final ExpectedException thrown = ExpectedException.none(); + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private final FakeClock fakeClock = new FakeClock(); + private final SynchronizationContext syncContext = new SynchronizationContext( + new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + throw new AssertionError(e); + } + }); + + @Mock + private Helper helper; + private LoadBalancer xdsLoadBalancer; + private AdsStreamCallback adsCallback; + + private Helper lookasideLbHelper; + private final List lookasideLbs = new ArrayList<>(); + + private Helper fallbackLbHelper; + private final List fallbackLbs = new ArrayList<>(); + + private int requestConnectionTimes; + + @Before + public void setUp() { + LookasideLbFactory lookasideLbFactory = new LookasideLbFactory() { + @Override + public LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback) { + // just return a mock and record the input and output + lookasideLbHelper = helper; + XdsLoadBalancer2Test.this.adsCallback = adsCallback; + LoadBalancer lookasideLb = mock(LoadBalancer.class); + lookasideLbs.add(lookasideLb); + return lookasideLb; + } + }; + LoadBalancer.Factory fallbackLbFactory = new LoadBalancer.Factory() { + @Override + public LoadBalancer newLoadBalancer(Helper helper) { + // just return a mock and record the input and output + fallbackLbHelper = helper; + LoadBalancer fallbackLb = mock(LoadBalancer.class); + fallbackLbs.add(fallbackLb); + return fallbackLb; + } + }; + doReturn(syncContext).when(helper).getSynchronizationContext(); + doReturn(fakeClock.getScheduledExecutorService()).when(helper).getScheduledExecutorService(); + doReturn(mock(ChannelLogger.class)).when(helper).getChannelLogger(); + + xdsLoadBalancer = + new XdsLoadBalancer2(helper, lookasideLbFactory, fallbackLbFactory); + xdsLoadBalancer.handleResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()).build()); + } + + @Test + public void tearDown() { + assertThat(lookasideLbs).hasSize(1); + xdsLoadBalancer.shutdown(); + for (LoadBalancer lookasideLb : lookasideLbs) { + verify(lookasideLb).shutdown(); + } + for (LoadBalancer fallbackLb : fallbackLbs) { + verify(fallbackLb).shutdown(); + } + assertThat(fakeClock.getPendingTasks()).isEmpty(); + } + + @Test + public void canHandleEmptyAddressListFromNameResolution() { + assertThat(xdsLoadBalancer.canHandleEmptyAddressListFromNameResolution()).isTrue(); + } + + @Test + public void timeoutAtStartup_expectUseFallback_thenBackendReady_expectExitFallback() { + verifyNotInFallbackMode(); + fakeClock.forwardTime(9, TimeUnit.SECONDS); + adsCallback.onWorking(); + verifyNotInFallbackMode(); + fakeClock.forwardTime(1, TimeUnit.SECONDS); + verifyInFallbackMode(); + + SubchannelPicker subchannelPicker = mock(SubchannelPicker.class); + lookasideLbHelper.updateBalancingState(READY, subchannelPicker); + verify(helper).updateBalancingState(READY, subchannelPicker); + verifyNotInFallbackMode(); + + assertThat(fallbackLbs).hasSize(1); + } + + @Test + public void backendReadyBeforeTimeoutAtStartup_expectNoFallback() { + verifyNotInFallbackMode(); + fakeClock.forwardTime(9, TimeUnit.SECONDS); + verifyNotInFallbackMode(); + assertThat(fakeClock.getPendingTasks()).hasSize(1); + + adsCallback.onWorking(); + SubchannelPicker subchannelPicker = mock(SubchannelPicker.class); + lookasideLbHelper.updateBalancingState(READY, subchannelPicker); + verify(helper).updateBalancingState(READY, subchannelPicker); + assertThat(fakeClock.getPendingTasks()).isEmpty(); + verifyNotInFallbackMode(); + + assertThat(fallbackLbs).isEmpty(); + } + + @Test + public void recevieAllDropBeforeTimeoutAtStartup_expectNoFallback() { + verifyNotInFallbackMode(); + assertThat(fakeClock.getPendingTasks()).hasSize(1); + + adsCallback.onAllDrop(); + assertThat(fakeClock.getPendingTasks()).isEmpty(); + verifyNotInFallbackMode(); + + assertThat(fallbackLbs).isEmpty(); + } + + @Test + public void lookasideChannelFailsWithoutSeeingEdsResponseBeforeTimeoutAtStartup() { + verifyNotInFallbackMode(); + assertThat(fakeClock.getPendingTasks()).hasSize(1); + + adsCallback.onError(); + verifyInFallbackMode(); + + assertThat(fallbackLbs).hasSize(1); + } + + @Test + public void lookasideChannelSeeingEdsResponseThenFailsBeforeTimeoutAtStartup() { + verifyNotInFallbackMode(); + assertThat(fakeClock.getPendingTasks()).hasSize(1); + adsCallback.onWorking(); + adsCallback.onError(); + verifyNotInFallbackMode(); + + fakeClock.forwardTime(10, TimeUnit.SECONDS); + verifyInFallbackMode(); + + assertThat(fallbackLbs).hasSize(1); + } + + @Test + public void fallbackWillHandleLastResolvedAddresses() { + verifyNotInFallbackMode(); + + ResolvedAddresses resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()) + .setAttributes( + Attributes.newBuilder().set(Attributes.Key.create("k"), new Object()).build()) + .setLoadBalancingPolicyConfig(new Object()) + .build(); + xdsLoadBalancer.handleResolvedAddresses(resolvedAddresses); + + adsCallback.onError(); + LoadBalancer fallbackLb = Iterables.getLast(fallbackLbs); + verify(fallbackLb).handleResolvedAddresses(same(resolvedAddresses)); + } + + private void verifyInFallbackMode() { + assertThat(lookasideLbs).isNotEmpty(); + assertThat(fallbackLbs).isNotEmpty(); + LoadBalancer lookasideLb = Iterables.getLast(lookasideLbs); + LoadBalancer fallbackLb = Iterables.getLast(fallbackLbs); + verify(lookasideLb, never()).shutdown(); + verify(fallbackLb, never()).shutdown(); + + xdsLoadBalancer.requestConnection(); + verify(lookasideLb, times(++requestConnectionTimes)).requestConnection(); + verify(fallbackLb).requestConnection(); + + ResolvedAddresses resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()) + .setAttributes( + Attributes.newBuilder().set(Attributes.Key.create("k"), new Object()).build()) + .setLoadBalancingPolicyConfig(new Object()) + .build(); + xdsLoadBalancer.handleResolvedAddresses(resolvedAddresses); + verify(lookasideLb).handleResolvedAddresses(same(resolvedAddresses)); + verify(fallbackLb).handleResolvedAddresses(same(resolvedAddresses)); + + Status status = Status.DATA_LOSS.withDescription(""); + xdsLoadBalancer.handleNameResolutionError(status); + verify(lookasideLb).handleNameResolutionError(same(status)); + verify(fallbackLb).handleNameResolutionError(same(status)); + + SubchannelPicker subchannelPicker = mock(SubchannelPicker.class); + lookasideLbHelper.updateBalancingState(CONNECTING, subchannelPicker); + verify(helper, never()).updateBalancingState(CONNECTING, subchannelPicker); + fallbackLbHelper.updateBalancingState(CONNECTING, subchannelPicker); + verify(helper).updateBalancingState(CONNECTING, subchannelPicker); + } + + private void verifyNotInFallbackMode() { + for (LoadBalancer fallbackLb : fallbackLbs) { + verify(fallbackLb).shutdown(); + } + LoadBalancer lookasideLb = Iterables.getLast(lookasideLbs); + + xdsLoadBalancer.requestConnection(); + verify(lookasideLb, times(++requestConnectionTimes)).requestConnection(); + + ResolvedAddresses resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()) + .setAttributes( + Attributes.newBuilder().set(Attributes.Key.create("k"), new Object()).build()) + .setLoadBalancingPolicyConfig(new Object()) + .build(); + xdsLoadBalancer.handleResolvedAddresses(resolvedAddresses); + verify(lookasideLb).handleResolvedAddresses(same(resolvedAddresses)); + + Status status = Status.DATA_LOSS.withDescription(""); + xdsLoadBalancer.handleNameResolutionError(status); + verify(lookasideLb).handleNameResolutionError(same(status)); + + SubchannelPicker subchannelPicker = mock(SubchannelPicker.class); + lookasideLbHelper.updateBalancingState(CONNECTING, subchannelPicker); + verify(helper).updateBalancingState(CONNECTING, subchannelPicker); + } + + @Deprecated + @Test + public void handleSubchannelState_shouldThrow() { + Subchannel subchannel = mock(Subchannel.class); + ConnectivityStateInfo connectivityStateInfo = ConnectivityStateInfo.forNonError(READY); + thrown.expect(UnsupportedOperationException.class); + xdsLoadBalancer.handleSubchannelState(subchannel, connectivityStateInfo); + } +} From df4da6bef3e94ea31dbe3574ad590eb411508a2b Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Mon, 16 Sep 2019 15:48:56 -0700 Subject: [PATCH 016/131] auth: removed unused import (#6155) --- .../java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java b/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java index b34451bcf94..634cc1e46de 100644 --- a/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java +++ b/auth/src/test/java/io/grpc/auth/GoogleAuthLibraryCallCredentialsTest.java @@ -54,7 +54,6 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; import java.util.ArrayList; -import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; From fd4f189d2b5562398e439878a9260ba99e095115 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Tue, 17 Sep 2019 11:01:45 -0700 Subject: [PATCH 017/131] Create a new class XdsAttributes in xds to house XDS related attributes and define ATTR_SDS_CONFIG there (#6154) Need to define a new attribute so we can plumb SdsSecretConfig from the xDS LB to SSL code so the value can be passed on to the SDS module. --- .../main/java/io/grpc/xds/XdsAttributes.java | 36 ++ xds/third_party/envoy/import.sh | 1 + .../main/proto/envoy/api/v2/auth/cert.proto | 407 ++++++++++++++++++ 3 files changed, 444 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/XdsAttributes.java create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto diff --git a/xds/src/main/java/io/grpc/xds/XdsAttributes.java b/xds/src/main/java/io/grpc/xds/XdsAttributes.java new file mode 100644 index 00000000000..9d590a2f910 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/XdsAttributes.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import io.envoyproxy.envoy.api.v2.auth.SdsSecretConfig; +import io.grpc.Attributes; +import io.grpc.Grpc; + +/** + * Special attributes that are only useful to gRPC in the XDS context + */ +final class XdsAttributes { + /** + * Attribute key for SdsSecretConfig of a subchannel. + * + */ + @Grpc.TransportAttr + public static final Attributes.Key ATTR_SDS_CONFIG = + Attributes.Key.create("io.grpc.xds.XdsAttributes.sdsSecretConfig"); + + private XdsAttributes() {} +} diff --git a/xds/third_party/envoy/import.sh b/xds/third_party/envoy/import.sh index 339d70de59f..c347a0ab73a 100755 --- a/xds/third_party/envoy/import.sh +++ b/xds/third_party/envoy/import.sh @@ -24,6 +24,7 @@ GIT_BASE_DIR=envoy SOURCE_PROTO_BASE_DIR=envoy/api TARGET_PROTO_BASE_DIR=src/main/proto FILES=( +envoy/api/v2/auth/cert.proto envoy/api/v2/core/address.proto envoy/api/v2/core/base.proto envoy/api/v2/core/config_source.proto diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto new file mode 100644 index 00000000000..30db22c6d7a --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto @@ -0,0 +1,407 @@ +syntax = "proto3"; + +package envoy.api.v2.auth; + +option java_outer_classname = "CertProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.auth"; +option go_package = "auth"; + +import "envoy/api/v2/core/base.proto"; +import "envoy/api/v2/core/config_source.proto"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; +import "gogoproto/gogo.proto"; + +option (gogoproto.equal_all) = true; + +// [#protodoc-title: Common TLS configuration] + +message TlsParameters { + enum TlsProtocol { + // Envoy will choose the optimal TLS version. + TLS_AUTO = 0; + + // TLS 1.0 + TLSv1_0 = 1; + + // TLS 1.1 + TLSv1_1 = 2; + + // TLS 1.2 + TLSv1_2 = 3; + + // TLS 1.3 + TLSv1_3 = 4; + } + + // Minimum TLS protocol version. By default, it's ``TLSv1_0``. + TlsProtocol tls_minimum_protocol_version = 1 [(validate.rules).enum.defined_only = true]; + + // Maximum TLS protocol version. By default, it's ``TLSv1_3`` for servers in non-FIPS builds, and + // ``TLSv1_2`` for clients and for servers using :ref:`BoringSSL FIPS `. + TlsProtocol tls_maximum_protocol_version = 2 [(validate.rules).enum.defined_only = true]; + + // If specified, the TLS listener will only support the specified `cipher list + // `_ + // when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). If not + // specified, the default list will be used. + // + // In non-FIPS builds, the default cipher list is: + // + // .. code-block:: none + // + // [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + // [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + // ECDHE-ECDSA-AES128-SHA + // ECDHE-RSA-AES128-SHA + // AES128-GCM-SHA256 + // AES128-SHA + // ECDHE-ECDSA-AES256-GCM-SHA384 + // ECDHE-RSA-AES256-GCM-SHA384 + // ECDHE-ECDSA-AES256-SHA + // ECDHE-RSA-AES256-SHA + // AES256-GCM-SHA384 + // AES256-SHA + // + // In builds using :ref:`BoringSSL FIPS `, the default cipher list is: + // + // .. code-block:: none + // + // ECDHE-ECDSA-AES128-GCM-SHA256 + // ECDHE-RSA-AES128-GCM-SHA256 + // ECDHE-ECDSA-AES128-SHA + // ECDHE-RSA-AES128-SHA + // AES128-GCM-SHA256 + // AES128-SHA + // ECDHE-ECDSA-AES256-GCM-SHA384 + // ECDHE-RSA-AES256-GCM-SHA384 + // ECDHE-ECDSA-AES256-SHA + // ECDHE-RSA-AES256-SHA + // AES256-GCM-SHA384 + // AES256-SHA + repeated string cipher_suites = 3; + + // If specified, the TLS connection will only support the specified ECDH + // curves. If not specified, the default curves will be used. + // + // In non-FIPS builds, the default curves are: + // + // .. code-block:: none + // + // X25519 + // P-256 + // + // In builds using :ref:`BoringSSL FIPS `, the default curve is: + // + // .. code-block:: none + // + // P-256 + repeated string ecdh_curves = 4; +} + +// BoringSSL private key method configuration. The private key methods are used for external +// (potentially asynchronous) signing and decryption operations. Some use cases for private key +// methods would be TPM support and TLS acceleration. +message PrivateKeyProvider { + // Private key method provider name. The name must match a + // supported private key method provider type. + string provider_name = 1 [(validate.rules).string.min_bytes = 1]; + + // Private key method provider specific configuration. + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } +} + +message TlsCertificate { + // The TLS certificate chain. + core.DataSource certificate_chain = 1; + + // The TLS private key. + core.DataSource private_key = 2; + + // BoringSSL private key method provider. This is an alternative to :ref:`private_key + // ` field. This can't be + // marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key + // ` and + // :ref:`private_key_provider + // ` fields will result in an + // error. + PrivateKeyProvider private_key_provider = 6; + + // The password to decrypt the TLS private key. If this field is not set, it is assumed that the + // TLS private key is not password encrypted. + core.DataSource password = 3; + + // [#not-implemented-hide:] + core.DataSource ocsp_staple = 4; + + // [#not-implemented-hide:] + repeated core.DataSource signed_certificate_timestamp = 5; +} + +message TlsSessionTicketKeys { + // Keys for encrypting and decrypting TLS session tickets. The + // first key in the array contains the key to encrypt all new sessions created by this context. + // All keys are candidates for decrypting received tickets. This allows for easy rotation of keys + // by, for example, putting the new key first, and the previous key second. + // + // If :ref:`session_ticket_keys ` + // is not specified, the TLS library will still support resuming sessions via tickets, but it will + // use an internally-generated and managed key, so sessions cannot be resumed across hot restarts + // or on different hosts. + // + // Each key must contain exactly 80 bytes of cryptographically-secure random data. For + // example, the output of ``openssl rand 80``. + // + // .. attention:: + // + // Using this feature has serious security considerations and risks. Improper handling of keys + // may result in loss of secrecy in connections, even if ciphers supporting perfect forward + // secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some + // discussion. To minimize the risk, you must: + // + // * Keep the session ticket keys at least as secure as your TLS certificate private keys + // * Rotate session ticket keys at least daily, and preferably hourly + // * Always generate keys using a cryptographically-secure random data source + repeated core.DataSource keys = 1 [(validate.rules).repeated .min_items = 1]; +} + +message CertificateValidationContext { + // TLS certificate data containing certificate authority certificates to use in verifying + // a presented peer certificate (e.g. server certificate for clusters or client certificate + // for listeners). If not specified and a peer certificate is presented it will not be + // verified. By default, a client certificate is optional, unless one of the additional + // options (:ref:`require_client_certificate + // `, + // :ref:`verify_certificate_spki + // `, + // :ref:`verify_certificate_hash + // `, or + // :ref:`verify_subject_alt_name + // `) is also + // specified. + // + // It can optionally contain certificate revocation lists, in which case Envoy will verify + // that the presented peer certificate has not been revoked by one of the included CRLs. + // + // See :ref:`the TLS overview ` for a list of common + // system CA locations. + core.DataSource trusted_ca = 1; + + // An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the + // SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate + // matches one of the specified values. + // + // A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate + // can be generated with the following command: + // + // .. code-block:: bash + // + // $ openssl x509 -in path/to/client.crt -noout -pubkey \ + // | openssl pkey -pubin -outform DER \ + // | openssl dgst -sha256 -binary \ + // | openssl enc -base64 + // NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= + // + // This is the format used in HTTP Public Key Pinning. + // + // When both: + // :ref:`verify_certificate_hash + // ` and + // :ref:`verify_certificate_spki + // ` are specified, + // a hash matching value from either of the lists will result in the certificate being accepted. + // + // .. attention:: + // + // This option is preferred over :ref:`verify_certificate_hash + // `, + // because SPKI is tied to a private key, so it doesn't change when the certificate + // is renewed using the same private key. + repeated string verify_certificate_spki = 3 + [(validate.rules).repeated .items.string = {min_bytes: 44, max_bytes: 44}]; + + // An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that + // the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + // + // A hex-encoded SHA-256 of the certificate can be generated with the following command: + // + // .. code-block:: bash + // + // $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 + // df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a + // + // A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate + // can be generated with the following command: + // + // .. code-block:: bash + // + // $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 + // DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A + // + // Both of those formats are acceptable. + // + // When both: + // :ref:`verify_certificate_hash + // ` and + // :ref:`verify_certificate_spki + // ` are specified, + // a hash matching value from either of the lists will result in the certificate being accepted. + repeated string verify_certificate_hash = 2 + [(validate.rules).repeated .items.string = {min_bytes: 64, max_bytes: 95}]; + + // An optional list of Subject Alternative Names. If specified, Envoy will verify that the + // Subject Alternative Name of the presented certificate matches one of the specified values. + // + // .. attention:: + // + // Subject Alternative Names are easily spoofable and verifying only them is insecure, + // therefore this option must be used together with :ref:`trusted_ca + // `. + repeated string verify_subject_alt_name = 4; + + // [#not-implemented-hide:] Must present a signed time-stamped OCSP response. + google.protobuf.BoolValue require_ocsp_staple = 5; + + // [#not-implemented-hide:] Must present signed certificate time-stamp. + google.protobuf.BoolValue require_signed_certificate_timestamp = 6; + + // An optional `certificate revocation list + // `_ + // (in PEM format). If specified, Envoy will verify that the presented peer + // certificate has not been revoked by this CRL. If this DataSource contains + // multiple CRLs, all of them will be used. + core.DataSource crl = 7; + + // If specified, Envoy will not reject expired certificates. + bool allow_expired_certificate = 8; +} + +// TLS context shared by both client and server TLS contexts. +message CommonTlsContext { + // TLS protocol versions, cipher suites etc. + TlsParameters tls_params = 1; + + // :ref:`Multiple TLS certificates ` can be associated with the + // same context to allow both RSA and ECDSA certificates. + // + // Only a single TLS certificate is supported in client contexts. In server contexts, the first + // RSA certificate is used for clients that only support RSA and the first ECDSA certificate is + // used for clients that support ECDSA. + repeated TlsCertificate tls_certificates = 2; + + // Configs for fetching TLS certificates via SDS API. + repeated SdsSecretConfig tls_certificate_sds_secret_configs = 6 + [(validate.rules).repeated .max_items = 1]; + + message CombinedCertificateValidationContext { + // How to validate peer certificates. + CertificateValidationContext default_validation_context = 1 + [(validate.rules).message.required = true]; + + // Config for fetching validation context via SDS API. + SdsSecretConfig validation_context_sds_secret_config = 2 + [(validate.rules).message.required = true]; + }; + + oneof validation_context_type { + // How to validate peer certificates. + CertificateValidationContext validation_context = 3; + + // Config for fetching validation context via SDS API. + SdsSecretConfig validation_context_sds_secret_config = 7; + + // Combined certificate validation context holds a default CertificateValidationContext + // and SDS config. When SDS server returns dynamic CertificateValidationContext, both dynamic + // and default CertificateValidationContext are merged into a new CertificateValidationContext + // for validation. This merge is done by Message::MergeFrom(), so dynamic + // CertificateValidationContext overwrites singular fields in default + // CertificateValidationContext, and concatenates repeated fields to default + // CertificateValidationContext, and logical OR is applied to boolean fields. + CombinedCertificateValidationContext combined_validation_context = 8; + } + + // Supplies the list of ALPN protocols that the listener should expose. In + // practice this is likely to be set to one of two values (see the + // :ref:`codec_type + // ` + // parameter in the HTTP connection manager for more information): + // + // * "h2,http/1.1" If the listener is going to support both HTTP/2 and HTTP/1.1. + // * "http/1.1" If the listener is only going to support HTTP/1.1. + // + // There is no default for this parameter. If empty, Envoy will not expose ALPN. + repeated string alpn_protocols = 4; + + reserved 5; +} + +message UpstreamTlsContext { + // Common TLS context settings. + CommonTlsContext common_tls_context = 1; + + // SNI string to use when creating TLS backend connections. + string sni = 2 [(validate.rules).string.max_bytes = 255]; + + // If true, server-initiated TLS renegotiation will be allowed. + // + // .. attention:: + // + // TLS renegotiation is considered insecure and shouldn't be used unless absolutely necessary. + bool allow_renegotiation = 3; + + // Maximum number of session keys (Pre-Shared Keys for TLSv1.3+, Session IDs and Session Tickets + // for TLSv1.2 and older) to store for the purpose of session resumption. + // + // Defaults to 1, setting this to 0 disables session resumption. + google.protobuf.UInt32Value max_session_keys = 4; +} + +message DownstreamTlsContext { + // Common TLS context settings. + CommonTlsContext common_tls_context = 1; + + // If specified, Envoy will reject connections without a valid client + // certificate. + google.protobuf.BoolValue require_client_certificate = 2; + + // If specified, Envoy will reject connections without a valid and matching SNI. + // [#not-implemented-hide:] + google.protobuf.BoolValue require_sni = 3; + + oneof session_ticket_keys_type { + // TLS session ticket key settings. + TlsSessionTicketKeys session_ticket_keys = 4; + + // [#not-implemented-hide:] + SdsSecretConfig session_ticket_keys_sds_secret_config = 5; + } +} + +// [#proto-status: experimental] +message SdsSecretConfig { + // Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + // When both name and config are specified, then secret can be fetched and/or reloaded via SDS. + // When only name is specified, then secret will be loaded from static resources [V2-API-DIFF]. + string name = 1; + core.ConfigSource sds_config = 2; +} + +// [#proto-status: experimental] +message Secret { + // Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + string name = 1; + oneof type { + TlsCertificate tls_certificate = 2; + TlsSessionTicketKeys session_ticket_keys = 3; + CertificateValidationContext validation_context = 4; + } +} From ba0fd84d79d66f46b4492043c62ecb0fcf85ead2 Mon Sep 17 00:00:00 2001 From: Anar Sultanov Date: Wed, 18 Sep 2019 00:59:29 +0200 Subject: [PATCH 018/131] netty: Rely on ChannelFactory in NettyServer instead of dynamic classes Fixes #5649 --- .../main/java/io/grpc/netty/NettyServer.java | 13 ++--- .../io/grpc/netty/NettyServerBuilder.java | 51 ++++++++++++++----- netty/src/main/java/io/grpc/netty/Utils.java | 17 +++++-- .../grpc/netty/NettyClientTransportTest.java | 2 +- .../java/io/grpc/netty/NettyServerTest.java | 8 +-- .../test/java/io/grpc/netty/UtilsTest.java | 10 ++-- 6 files changed, 70 insertions(+), 31 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/NettyServer.java b/netty/src/main/java/io/grpc/netty/NettyServer.java index 72c5c27db61..f0cfea99d7e 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServer.java +++ b/netty/src/main/java/io/grpc/netty/NettyServer.java @@ -38,6 +38,7 @@ import io.grpc.internal.TransportTracer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelInitializer; @@ -66,7 +67,7 @@ class NettyServer implements InternalServer, InternalWithLogId { private final InternalLogId logId; private final SocketAddress address; - private final Class channelType; + private final ChannelFactory channelFactory; private final Map, ?> channelOptions; private final ProtocolNegotiator protocolNegotiator; private final int maxStreamsPerConnection; @@ -95,7 +96,7 @@ class NettyServer implements InternalServer, InternalWithLogId { new AtomicReference<>(); NettyServer( - SocketAddress address, Class channelType, + SocketAddress address, ChannelFactory channelFactory, Map, ?> channelOptions, ObjectPool bossGroupPool, ObjectPool workerGroupPool, @@ -109,7 +110,7 @@ class NettyServer implements InternalServer, InternalWithLogId { boolean permitKeepAliveWithoutCalls, long permitKeepAliveTimeInNanos, InternalChannelz channelz) { this.address = address; - this.channelType = checkNotNull(channelType, "channelType"); + this.channelFactory = checkNotNull(channelFactory, "channelFactory"); checkNotNull(channelOptions, "channelOptions"); this.channelOptions = new HashMap, Object>(channelOptions); this.bossGroupPool = checkNotNull(bossGroupPool, "bossGroupPool"); @@ -155,7 +156,7 @@ public void start(ServerListener serverListener) throws IOException { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup); - b.channel(channelType); + b.channelFactory(channelFactory); // For non-socket based channel, the option will be ignored. b.option(SO_BACKLOG, 128); b.childOption(SO_KEEPALIVE, true); @@ -170,7 +171,7 @@ public void start(ServerListener serverListener) throws IOException { b.childHandler(new ChannelInitializer() { @Override - public void initChannel(Channel ch) throws Exception { + public void initChannel(Channel ch) { ChannelPromise channelDone = ch.newPromise(); @@ -217,7 +218,7 @@ public void initChannel(Channel ch) throws Exception { * Releases the event loop if the channel is "done", possibly due to the channel closing. */ final class LoopReleaser implements ChannelFutureListener { - boolean done; + private boolean done; @Override public void operationComplete(ChannelFuture future) throws Exception { diff --git a/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java b/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java index 94d68f2441f..22fab43a2eb 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerBuilder.java @@ -25,7 +25,6 @@ import static io.grpc.internal.GrpcUtil.SERVER_KEEPALIVE_TIME_NANOS_DISABLED; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.grpc.ExperimentalApi; import io.grpc.Internal; @@ -36,8 +35,10 @@ import io.grpc.internal.KeepAliveManager; import io.grpc.internal.ObjectPool; import io.grpc.internal.SharedResourcePool; +import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; +import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.ServerChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.ssl.SslContext; @@ -79,7 +80,9 @@ public final class NettyServerBuilder extends AbstractServerImplBuilder listenAddresses = new ArrayList<>(); - private Class channelType = null; + + private ChannelFactory channelFactory = + Utils.DEFAULT_SERVER_CHANNEL_FACTORY; private final Map, Object> channelOptions = new HashMap<>(); private ObjectPool bossEventLoopGroupPool = DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL; @@ -91,7 +94,7 @@ public final class NettyServerBuilder extends AbstractServerImplBuilderYou either use this or {@link #channelFactory(io.netty.channel.ChannelFactory)} if your + * {@link ServerChannel} implementation has no no-args constructor. + * + *

It's an optional parameter. If the user has not provided an Channel type or ChannelFactory + * when the channel is built, the builder will use the default one which is static. * *

You must also provide corresponding {@link EventLoopGroup} using {@link * #workerEventLoopGroup(EventLoopGroup)} and {@link #bossEventLoopGroup(EventLoopGroup)}. For @@ -151,7 +160,26 @@ public NettyServerBuilder addListenAddress(SocketAddress listenAddress) { * io.netty.channel.nio.NioEventLoopGroup}, otherwise your server won't start. */ public NettyServerBuilder channelType(Class channelType) { - this.channelType = Preconditions.checkNotNull(channelType, "channelType"); + checkNotNull(channelType, "channelType"); + return channelFactory(new ReflectiveChannelFactory<>(channelType)); + } + + /** + * Specifies the {@link ChannelFactory} to create {@link ServerChannel} instances. This method is + * usually only used if the specific {@code ServerChannel} requires complex logic which requires + * additional information to create the {@code ServerChannel}. Otherwise, recommend to use {@link + * #channelType(Class)}. + * + *

It's an optional parameter. If the user has not provided an Channel type or ChannelFactory + * when the channel is built, the builder will use the default one which is static. + * + *

You must also provide corresponding {@link EventLoopGroup} using {@link + * #workerEventLoopGroup(EventLoopGroup)} and {@link #bossEventLoopGroup(EventLoopGroup)}. For + * example, if the factory creates {@link NioServerSocketChannel} you must use {@link + * io.netty.channel.nio.NioEventLoopGroup}, otherwise your server won't start. + */ + public NettyServerBuilder channelFactory(ChannelFactory channelFactory) { + this.channelFactory = checkNotNull(channelFactory, "channelFactory"); return this; } @@ -499,16 +527,13 @@ protected List buildTransportServers( ProtocolNegotiator negotiator = protocolNegotiator; if (negotiator == null) { negotiator = sslContext != null ? ProtocolNegotiators.serverTls(sslContext) : - ProtocolNegotiators.serverPlaintext(); + ProtocolNegotiators.serverPlaintext(); } - Class resolvedChannelType = - channelType == null ? Utils.DEFAULT_SERVER_CHANNEL_TYPE : channelType; - List transportServers = new ArrayList<>(listenAddresses.size()); for (SocketAddress listenAddress : listenAddresses) { NettyServer transportServer = new NettyServer( - listenAddress, resolvedChannelType, channelOptions, bossEventLoopGroupPool, + listenAddress, channelFactory, channelOptions, bossEventLoopGroupPool, workerEventLoopGroupPool, negotiator, streamTracerFactories, getTransportTracerFactory(), maxConcurrentCallsPerConnection, flowControlWindow, maxMessageSize, maxHeaderListSize, keepAliveTimeInNanos, keepAliveTimeoutInNanos, @@ -521,10 +546,10 @@ protected List buildTransportServers( @VisibleForTesting void assertEventLoopsAndChannelType() { - boolean allProvided = channelType != null + boolean allProvided = channelFactory != Utils.DEFAULT_SERVER_CHANNEL_FACTORY && bossEventLoopGroupPool != DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL && workerEventLoopGroupPool != DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL; - boolean nonProvided = channelType == null + boolean nonProvided = channelFactory == Utils.DEFAULT_SERVER_CHANNEL_FACTORY && bossEventLoopGroupPool == DEFAULT_BOSS_EVENT_LOOP_GROUP_POOL && workerEventLoopGroupPool == DEFAULT_WORKER_EVENT_LOOP_GROUP_POOL; checkState( diff --git a/netty/src/main/java/io/grpc/netty/Utils.java b/netty/src/main/java/io/grpc/netty/Utils.java index 76f40b00cc8..41d5699ea78 100644 --- a/netty/src/main/java/io/grpc/netty/Utils.java +++ b/netty/src/main/java/io/grpc/netty/Utils.java @@ -36,8 +36,10 @@ import io.grpc.netty.NettySocketSupport.NativeSocketOptions; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; +import io.netty.channel.ReflectiveChannelFactory; import io.netty.channel.ServerChannel; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel; @@ -81,7 +83,7 @@ class Utils { public static final Resource DEFAULT_BOSS_EVENT_LOOP_GROUP; public static final Resource DEFAULT_WORKER_EVENT_LOOP_GROUP; - public static final Class DEFAULT_SERVER_CHANNEL_TYPE; + public static final ChannelFactory DEFAULT_SERVER_CHANNEL_FACTORY; public static final Class DEFAULT_CLIENT_CHANNEL_TYPE; @Nullable @@ -90,8 +92,8 @@ class Utils { static { // Decide default channel types and EventLoopGroup based on Epoll availability if (isEpollAvailable()) { - DEFAULT_SERVER_CHANNEL_TYPE = epollServerChannelType(); DEFAULT_CLIENT_CHANNEL_TYPE = epollChannelType(); + DEFAULT_SERVER_CHANNEL_FACTORY = new ReflectiveChannelFactory<>(epollServerChannelType()); EPOLL_EVENT_LOOP_GROUP_CONSTRUCTOR = epollEventLoopGroupConstructor(); DEFAULT_BOSS_EVENT_LOOP_GROUP = new DefaultEventLoopGroupResource(1, "grpc-default-boss-ELG", EventLoopGroupType.EPOLL); @@ -99,7 +101,7 @@ class Utils { = new DefaultEventLoopGroupResource(0,"grpc-default-worker-ELG", EventLoopGroupType.EPOLL); } else { logger.log(Level.FINE, "Epoll is not available, using Nio.", getEpollUnavailabilityCause()); - DEFAULT_SERVER_CHANNEL_TYPE = NioServerSocketChannel.class; + DEFAULT_SERVER_CHANNEL_FACTORY = nioServerChannelFactory(); DEFAULT_CLIENT_CHANNEL_TYPE = NioSocketChannel.class; DEFAULT_BOSS_EVENT_LOOP_GROUP = NIO_BOSS_EVENT_LOOP_GROUP; DEFAULT_WORKER_EVENT_LOOP_GROUP = NIO_WORKER_EVENT_LOOP_GROUP; @@ -290,6 +292,15 @@ private static EventLoopGroup createEpollEventLoopGroup( } } + private static ChannelFactory nioServerChannelFactory() { + return new ChannelFactory() { + @Override + public ServerChannel newChannel() { + return new NioServerSocketChannel(); + } + }; + } + /** * Returns TCP_USER_TIMEOUT channel option for Epoll channel if Epoll is available, otherwise * null. diff --git a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java index 75e40bb2449..a32f7e06ede 100644 --- a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java @@ -719,7 +719,7 @@ private void startServer() throws IOException { private void startServer(int maxStreamsPerConnection, int maxHeaderListSize) throws IOException { server = new NettyServer( TestUtils.testServerAddress(new InetSocketAddress(0)), - NioServerSocketChannel.class, + new ReflectiveChannelFactory<>(NioServerSocketChannel.class), new HashMap, Object>(), new FixedObjectPool<>(group), new FixedObjectPool<>(group), negotiator, Collections.emptyList(), diff --git a/netty/src/test/java/io/grpc/netty/NettyServerTest.java b/netty/src/test/java/io/grpc/netty/NettyServerTest.java index b4fa966c498..51f0a50f27e 100644 --- a/netty/src/test/java/io/grpc/netty/NettyServerTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyServerTest.java @@ -58,7 +58,7 @@ public void getPort() throws Exception { InetSocketAddress addr = new InetSocketAddress(0); NettyServer ns = new NettyServer( addr, - Utils.DEFAULT_SERVER_CHANNEL_TYPE, + Utils.DEFAULT_SERVER_CHANNEL_FACTORY, new HashMap, Object>(), SharedResourcePool.forResource(Utils.DEFAULT_BOSS_EVENT_LOOP_GROUP), SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP), @@ -96,7 +96,7 @@ public void getPort_notStarted() throws Exception { InetSocketAddress addr = new InetSocketAddress(0); NettyServer ns = new NettyServer( addr, - Utils.DEFAULT_SERVER_CHANNEL_TYPE, + Utils.DEFAULT_SERVER_CHANNEL_FACTORY, new HashMap, Object>(), SharedResourcePool.forResource(Utils.DEFAULT_BOSS_EVENT_LOOP_GROUP), SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP), @@ -134,7 +134,7 @@ public void childChannelOptions() throws Exception { InetSocketAddress addr = new InetSocketAddress(0); NettyServer ns = new NettyServer( addr, - Utils.DEFAULT_SERVER_CHANNEL_TYPE, + Utils.DEFAULT_SERVER_CHANNEL_FACTORY, channelOptions, SharedResourcePool.forResource(Utils.DEFAULT_BOSS_EVENT_LOOP_GROUP), SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP), @@ -184,7 +184,7 @@ public void channelzListenSocket() throws Exception { InetSocketAddress addr = new InetSocketAddress(0); NettyServer ns = new NettyServer( addr, - Utils.DEFAULT_SERVER_CHANNEL_TYPE, + Utils.DEFAULT_SERVER_CHANNEL_FACTORY, new HashMap, Object>(), SharedResourcePool.forResource(Utils.DEFAULT_BOSS_EVENT_LOOP_GROUP), SharedResourcePool.forResource(Utils.DEFAULT_WORKER_EVENT_LOOP_GROUP), diff --git a/netty/src/test/java/io/grpc/netty/UtilsTest.java b/netty/src/test/java/io/grpc/netty/UtilsTest.java index bb66d29c2a0..c5d51138505 100644 --- a/netty/src/test/java/io/grpc/netty/UtilsTest.java +++ b/netty/src/test/java/io/grpc/netty/UtilsTest.java @@ -29,9 +29,11 @@ import io.grpc.Status; import io.grpc.internal.GrpcUtil; import io.netty.channel.Channel; +import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelOption; import io.netty.channel.ConnectTimeoutException; import io.netty.channel.EventLoopGroup; +import io.netty.channel.ServerChannel; import io.netty.channel.WriteBufferWaterMark; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.channel.socket.nio.NioSocketChannel; @@ -204,13 +206,13 @@ public void defaultClientChannelType_whenEpollIsAvailable() { } @Test - public void defaultServerChannelType_whenEpollIsAvailable() { + public void defaultServerChannelFactory_whenEpollIsAvailable() { assume().that(Utils.isEpollAvailable()).isTrue(); - Class clientChannelType = Utils.DEFAULT_SERVER_CHANNEL_TYPE; + ChannelFactory channelFactory = Utils.DEFAULT_SERVER_CHANNEL_FACTORY; - assertThat(clientChannelType.getName()) - .isEqualTo("io.netty.channel.epoll.EpollServerSocketChannel"); + assertThat(channelFactory.toString()) + .isEqualTo("ReflectiveChannelFactory(EpollServerSocketChannel.class)"); } @Test From a04ad9088875f77d7054f8f4103c82b3e06d7be7 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Wed, 18 Sep 2019 13:24:56 -0700 Subject: [PATCH 019/131] examples: clarify about potential mistake in unit test Resolves #6161 --- examples/README.md | 8 +++++--- .../examples/helloworld/HelloWorldClientTest.kt | 11 +++++++++-- .../examples/helloworld/HelloWorldClientTest.java | 13 ++++++++++++- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/examples/README.md b/examples/README.md index d98fc0d72d3..a5fa1e1b681 100644 --- a/examples/README.md +++ b/examples/README.md @@ -164,9 +164,11 @@ $ bazel-bin/hello-world-client Examples for unit testing gRPC clients and servers are located in [examples/src/test](src/test). -In general, we DO NOT allow overriding the client stub. -We encourage users to leverage `InProcessTransport` as demonstrated in the examples to -write unit tests. `InProcessTransport` is light-weight and runs the server +In general, we DO NOT allow overriding the client stub and we DO NOT support mocking final methods +in gRPC-Java library. Users should be cautious that using tools like PowerMock or +[mockito-inline](https://search.maven.org/search?q=g:org.mockito%20a:mockito-inline) can easily +break this rule of thumb. We encourage users to leverage `InProcessTransport` as demonstrated in the +examples to write unit tests. `InProcessTransport` is light-weight and runs the server and client in the same process without any socket/TCP connection. Mocking the client stub provides a false sense of security when writing tests. Mocking stubs and responses diff --git a/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt index a3f9ce54b76..ffd06feaabc 100644 --- a/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt +++ b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt @@ -52,9 +52,16 @@ class HelloWorldClientTest { @get:Rule val grpcCleanup = GrpcCleanupRule() - private val serviceImpl = mock(GreeterGrpc.GreeterImplBase::class.java, delegatesTo(object : GreeterGrpc.GreeterImplBase() { + private val serviceImpl = mock(GreeterGrpc.GreeterImplBase::class.java, delegatesTo( + object : GreeterGrpc.GreeterImplBase() { + // By default the client will receive Status.UNIMPLEMENTED for all RPCs. + // You might need to implement necessary behaviors for your test here, like this: + // + // override fun sayHello(req: HelloRequest, respObserver: StreamObserver) { + // respObserver.onNext(HelloReply.getDefaultInstance()) + // respObserver.onCompleted() + })) - })) private var client: HelloWorldClient? = null @Before diff --git a/examples/src/test/java/io/grpc/examples/helloworld/HelloWorldClientTest.java b/examples/src/test/java/io/grpc/examples/helloworld/HelloWorldClientTest.java index 4ba747dcd27..d0262d687ee 100644 --- a/examples/src/test/java/io/grpc/examples/helloworld/HelloWorldClientTest.java +++ b/examples/src/test/java/io/grpc/examples/helloworld/HelloWorldClientTest.java @@ -56,7 +56,18 @@ public class HelloWorldClientTest { public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule(); private final GreeterGrpc.GreeterImplBase serviceImpl = - mock(GreeterGrpc.GreeterImplBase.class, delegatesTo(new GreeterGrpc.GreeterImplBase() {})); + mock(GreeterGrpc.GreeterImplBase.class, delegatesTo( + new GreeterGrpc.GreeterImplBase() { + // By default the client will receive Status.UNIMPLEMENTED for all RPCs. + // You might need to implement necessary behaviors for your test here, like this: + // + // @Override + // public void sayHello(HelloRequest request, StreamObserver respObserver) { + // respObserver.onNext(HelloReply.getDefaultInstance()); + // respObserver.onCompleted(); + // } + })); + private HelloWorldClient client; @Before From 19b09160c9fca721b103d5033ccc5d507eaa10d6 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Wed, 18 Sep 2019 15:16:31 -0700 Subject: [PATCH 020/131] all: stabilize ManagedChannelBuilder.usePlaintext() --- api/src/main/java/io/grpc/ManagedChannelBuilder.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index 9362a0db210..bd07f045b62 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -181,15 +181,12 @@ public T usePlaintext(boolean skipNegotiation) { *

This assumes prior knowledge that the target of this channel is using plaintext. It will * not perform HTTP/1.1 upgrades. * - * - * @throws UnsupportedOperationException if plaintext mode is not supported. * @return this + * @throws UnsupportedOperationException if plaintext mode is not supported. * @since 1.11.0 */ - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1772") - @SuppressWarnings("deprecation") public T usePlaintext() { - return usePlaintext(true); + throw new UnsupportedOperationException(); } /** From 16392bc7333f17451068d940765d3dc72d1b587a Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 19 Sep 2019 15:29:03 -0700 Subject: [PATCH 021/131] netty: converts Proxy handler into new protocol negotiation style (#6159) --- .../netty/InternalProtocolNegotiators.java | 15 - .../io/grpc/netty/ProtocolNegotiators.java | 272 +++--------------- .../grpc/netty/NettyClientTransportTest.java | 18 +- .../grpc/netty/ProtocolNegotiatorsTest.java | 44 ++- 4 files changed, 71 insertions(+), 278 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/InternalProtocolNegotiators.java b/netty/src/main/java/io/grpc/netty/InternalProtocolNegotiators.java index a889a040da6..e71a69559bc 100644 --- a/netty/src/main/java/io/grpc/netty/InternalProtocolNegotiators.java +++ b/netty/src/main/java/io/grpc/netty/InternalProtocolNegotiators.java @@ -19,7 +19,6 @@ import io.grpc.ChannelLogger; import io.grpc.netty.ProtocolNegotiators.ClientTlsHandler; import io.grpc.netty.ProtocolNegotiators.GrpcNegotiationHandler; -import io.grpc.netty.ProtocolNegotiators.ProtocolNegotiationHandler; import io.grpc.netty.ProtocolNegotiators.WaitUntilActiveHandler; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; @@ -40,20 +39,6 @@ public static ChannelLogger negotiationLogger(ChannelHandlerContext ctx) { return ProtocolNegotiators.negotiationLogger(ctx); } - /** - * Buffers all writes until either {@link #writeBufferedAndRemove(ChannelHandlerContext)} or - * {@link #fail(ChannelHandlerContext, Throwable)} is called. This handler allows us to - * write to a {@link io.netty.channel.Channel} before we are allowed to write to it officially - * i.e. before it's active or the TLS Handshake is complete. - */ - public abstract static class AbstractBufferingHandler - extends ProtocolNegotiators.AbstractBufferingHandler { - - protected AbstractBufferingHandler(ChannelHandler... handlers) { - super(handlers); - } - } - /** * Returns a {@link ProtocolNegotiator} that ensures the pipeline is set up so that TLS will * be negotiated, the {@code handler} is added and writes to the {@link io.netty.channel.Channel} diff --git a/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java b/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java index 51c30fd14d8..feeaf9cf358 100644 --- a/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java +++ b/netty/src/main/java/io/grpc/netty/ProtocolNegotiators.java @@ -34,13 +34,10 @@ import io.grpc.internal.GrpcAttributes; import io.grpc.internal.GrpcUtil; import io.netty.channel.ChannelDuplexHandler; -import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; -import io.netty.channel.ChannelInboundHandler; import io.netty.channel.ChannelInboundHandlerAdapter; -import io.netty.channel.ChannelPromise; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.HttpClientCodec; import io.netty.handler.codec.http.HttpClientUpgradeHandler; @@ -50,7 +47,6 @@ import io.netty.handler.codec.http2.Http2ClientUpgradeCodec; import io.netty.handler.proxy.HttpProxyHandler; import io.netty.handler.proxy.ProxyConnectionEvent; -import io.netty.handler.proxy.ProxyHandler; import io.netty.handler.ssl.OpenSsl; import io.netty.handler.ssl.OpenSslEngine; import io.netty.handler.ssl.SslContext; @@ -59,12 +55,9 @@ import io.netty.util.AsciiString; import io.netty.util.Attribute; import io.netty.util.AttributeMap; -import io.netty.util.ReferenceCountUtil; import java.net.SocketAddress; import java.net.URI; -import java.util.ArrayDeque; import java.util.Arrays; -import java.util.Queue; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; @@ -195,20 +188,16 @@ private void fireProtocolNegotiationEvent(ChannelHandlerContext ctx, SSLSession public static ProtocolNegotiator httpProxy(final SocketAddress proxyAddress, final @Nullable String proxyUsername, final @Nullable String proxyPassword, final ProtocolNegotiator negotiator) { + checkNotNull(negotiator, "negotiator"); + checkNotNull(proxyAddress, "proxyAddress"); final AsciiString scheme = negotiator.scheme(); - Preconditions.checkNotNull(proxyAddress, "proxyAddress"); - Preconditions.checkNotNull(negotiator, "negotiator"); class ProxyNegotiator implements ProtocolNegotiator { @Override public ChannelHandler newHandler(GrpcHttp2ConnectionHandler http2Handler) { - HttpProxyHandler proxyHandler; - if (proxyUsername == null || proxyPassword == null) { - proxyHandler = new HttpProxyHandler(proxyAddress); - } else { - proxyHandler = new HttpProxyHandler(proxyAddress, proxyUsername, proxyPassword); - } - return new BufferUntilProxyTunnelledHandler( - proxyHandler, negotiator.newHandler(http2Handler)); + ChannelHandler protocolNegotiationHandler = negotiator.newHandler(http2Handler); + ChannelHandler ppnh = new ProxyProtocolNegotiationHandler( + proxyAddress, proxyUsername, proxyPassword, protocolNegotiationHandler); + return ppnh; } @Override @@ -228,34 +217,45 @@ public void close() { } /** - * Buffers all writes until the HTTP CONNECT tunnel is established. + * A Proxy handler follows {@link ProtocolNegotiationHandler} pattern. Upon successful proxy + * connection, this handler will install {@code next} handler which should be a handler from + * other type of {@link ProtocolNegotiator} to continue negotiating protocol using proxy. */ - static final class BufferUntilProxyTunnelledHandler extends AbstractBufferingHandler { + static final class ProxyProtocolNegotiationHandler extends ProtocolNegotiationHandler { - public BufferUntilProxyTunnelledHandler(ProxyHandler proxyHandler, ChannelHandler handler) { - super(proxyHandler, handler); - } + private final SocketAddress address; + @Nullable private final String userName; + @Nullable private final String password; - @Override - public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { - if (evt instanceof ProxyConnectionEvent) { - writeBufferedAndRemove(ctx); - } - super.userEventTriggered(ctx, evt); + public ProxyProtocolNegotiationHandler( + SocketAddress address, + @Nullable String userName, + @Nullable String password, + ChannelHandler next) { + super(next); + this.address = checkNotNull(address, "address"); + this.userName = userName; + this.password = password; } @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - fail(ctx, unavailableException("Connection broken while trying to CONNECT through proxy")); - super.channelInactive(ctx); + protected void protocolNegotiationEventTriggered(ChannelHandlerContext ctx) { + HttpProxyHandler nettyProxyHandler; + if (userName == null || password == null) { + nettyProxyHandler = new HttpProxyHandler(address); + } else { + nettyProxyHandler = new HttpProxyHandler(address, userName, password); + } + ctx.pipeline().addBefore(ctx.name(), /* newName= */ null, nettyProxyHandler); } @Override - public void close(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { - if (ctx.channel().isActive()) { // This may be a notification that the socket was closed - fail(ctx, unavailableException("Channel closed while trying to CONNECT through proxy")); + protected void userEventTriggered0(ChannelHandlerContext ctx, Object evt) throws Exception { + if (evt instanceof ProxyConnectionEvent) { + fireProtocolNegotiationEvent(ctx); + } else { + super.userEventTriggered(ctx, evt); } - super.close(ctx, future); } } @@ -527,208 +527,6 @@ static void logSslEngineDetails(Level level, ChannelHandlerContext ctx, String m log.log(level, builder.toString(), t); } - /** - * Buffers all writes until either {@link #writeBufferedAndRemove(ChannelHandlerContext)} or - * {@link #fail(ChannelHandlerContext, Throwable)} is called. This handler allows us to - * write to a {@link io.netty.channel.Channel} before we are allowed to write to it officially - * i.e. before it's active or the TLS Handshake is complete. - */ - public abstract static class AbstractBufferingHandler extends ChannelDuplexHandler { - - private ChannelHandler[] handlers; - private Queue bufferedWrites = new ArrayDeque<>(); - private boolean writing; - private boolean flushRequested; - private Throwable failCause; - - /** - * @param handlers the ChannelHandlers are added to the pipeline on channelRegistered and - * before this handler. - */ - protected AbstractBufferingHandler(ChannelHandler... handlers) { - this.handlers = handlers; - } - - /** - * When this channel is registered, we will add all the ChannelHandlers passed into our - * constructor to the pipeline. - */ - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - /** - * This check is necessary as a channel may be registered with different event loops during it - * lifetime and we only want to configure it once. - */ - if (handlers != null && handlers.length > 0) { - for (ChannelHandler handler : handlers) { - ctx.pipeline().addBefore(ctx.name(), null, handler); - } - ChannelHandler handler0 = handlers[0]; - ChannelHandlerContext handler0Ctx = ctx.pipeline().context(handlers[0]); - handlers = null; - if (handler0Ctx != null) { // The handler may have removed itself immediately - if (handler0 instanceof ChannelInboundHandler) { - ((ChannelInboundHandler) handler0).channelRegistered(handler0Ctx); - } else { - handler0Ctx.fireChannelRegistered(); - } - } - } else { - super.channelRegistered(ctx); - } - } - - /** - * Do not rely on channel handlers to propagate exceptions to us. - * {@link NettyClientHandler} is an example of a class that does not propagate exceptions. - * Add a listener to the connect future directly and do appropriate error handling. - */ - @Override - public void connect(final ChannelHandlerContext ctx, SocketAddress remoteAddress, - SocketAddress localAddress, ChannelPromise promise) throws Exception { - super.connect(ctx, remoteAddress, localAddress, promise); - promise.addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture future) throws Exception { - if (!future.isSuccess()) { - fail(ctx, future.cause()); - } - } - }); - } - - /** - * If we encounter an exception, then notify all buffered writes that we failed. - */ - @Override - public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { - fail(ctx, cause); - } - - /** - * If this channel becomes inactive, then notify all buffered writes that we failed. - */ - @Override - public void channelInactive(ChannelHandlerContext ctx) throws Exception { - fail(ctx, unavailableException("Connection broken while performing protocol negotiation")); - super.channelInactive(ctx); - } - - /** - * Buffers the write until either {@link #writeBufferedAndRemove(ChannelHandlerContext)} is - * called, or we have somehow failed. If we have already failed in the past, then the write - * will fail immediately. - */ - @Override - @SuppressWarnings("FutureReturnValueIgnored") - public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) - throws Exception { - /** - * This check handles a race condition between Channel.write (in the calling thread) and the - * removal of this handler (in the event loop thread). - * The problem occurs in e.g. this sequence: - * 1) [caller thread] The write method identifies the context for this handler - * 2) [event loop] This handler removes itself from the pipeline - * 3) [caller thread] The write method delegates to the invoker to call the write method in - * the event loop thread. When this happens, we identify that this handler has been - * removed with "bufferedWrites == null". - */ - if (failCause != null) { - promise.setFailure(failCause); - ReferenceCountUtil.release(msg); - } else if (bufferedWrites == null) { - super.write(ctx, msg, promise); - } else { - bufferedWrites.add(new ChannelWrite(msg, promise)); - } - } - - /** - * Calls to this method will not trigger an immediate flush. The flush will be deferred until - * {@link #writeBufferedAndRemove(ChannelHandlerContext)}. - */ - @Override - public void flush(ChannelHandlerContext ctx) { - /** - * Swallowing any flushes is not only an optimization but also required - * for the SslHandler to work correctly. If the SslHandler receives multiple - * flushes while the handshake is still ongoing, then the handshake "randomly" - * times out. Not sure at this point why this is happening. Doing a single flush - * seems to work but multiple flushes don't ... - */ - if (bufferedWrites == null) { - ctx.flush(); - } else { - flushRequested = true; - } - } - - /** - * If we are still performing protocol negotiation, then this will propagate failures to all - * buffered writes. - */ - @Override - public void close(ChannelHandlerContext ctx, ChannelPromise future) throws Exception { - if (ctx.channel().isActive()) { // This may be a notification that the socket was closed - fail(ctx, unavailableException("Channel closed while performing protocol negotiation")); - } - super.close(ctx, future); - } - - /** - * Propagate failures to all buffered writes. - */ - @SuppressWarnings("FutureReturnValueIgnored") - protected final void fail(ChannelHandlerContext ctx, Throwable cause) { - if (failCause == null) { - failCause = cause; - } - if (bufferedWrites != null) { - while (!bufferedWrites.isEmpty()) { - ChannelWrite write = bufferedWrites.poll(); - write.promise.setFailure(cause); - ReferenceCountUtil.release(write.msg); - } - bufferedWrites = null; - } - - ctx.fireExceptionCaught(cause); - } - - @SuppressWarnings("FutureReturnValueIgnored") - protected final void writeBufferedAndRemove(ChannelHandlerContext ctx) { - if (!ctx.channel().isActive() || writing) { - return; - } - // Make sure that method can't be reentered, so that the ordering - // in the queue can't be messed up. - writing = true; - while (!bufferedWrites.isEmpty()) { - ChannelWrite write = bufferedWrites.poll(); - ctx.write(write.msg, write.promise); - } - assert bufferedWrites.isEmpty(); - bufferedWrites = null; - if (flushRequested) { - ctx.flush(); - } - // Removal has to happen last as the above writes will likely trigger - // new writes that have to be added to the end of queue in order to not - // mess up the ordering. - ctx.pipeline().remove(this); - } - - private static class ChannelWrite { - Object msg; - ChannelPromise promise; - - ChannelWrite(Object msg, ChannelPromise promise) { - this.msg = msg; - this.promise = promise; - } - } - } - /** * Adapts a {@link ProtocolNegotiationEvent} to the {@link GrpcHttp2ConnectionHandler}. */ diff --git a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java index a32f7e06ede..ea46bac159a 100644 --- a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java @@ -67,8 +67,10 @@ import io.grpc.netty.NettyChannelBuilder.LocalSocketPicker; import io.netty.channel.Channel; import io.netty.channel.ChannelConfig; +import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFactory; import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.ReflectiveChannelFactory; @@ -915,9 +917,21 @@ public String parse(InputStream stream) { } } - private static class NoopHandler extends ProtocolNegotiators.AbstractBufferingHandler { + private static class NoopHandler extends ChannelDuplexHandler { + + private final GrpcHttp2ConnectionHandler grpcHandler; + public NoopHandler(GrpcHttp2ConnectionHandler grpcHandler) { - super(grpcHandler); + this.grpcHandler = grpcHandler; + } + + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + ctx.pipeline().addBefore(ctx.name(), null, grpcHandler); + } + + public void fail(ChannelHandlerContext ctx, Throwable cause) { + ctx.fireExceptionCaught(cause); } } diff --git a/netty/src/test/java/io/grpc/netty/ProtocolNegotiatorsTest.java b/netty/src/test/java/io/grpc/netty/ProtocolNegotiatorsTest.java index 6c9f3526376..8fde613fff9 100644 --- a/netty/src/test/java/io/grpc/netty/ProtocolNegotiatorsTest.java +++ b/netty/src/test/java/io/grpc/netty/ProtocolNegotiatorsTest.java @@ -35,7 +35,6 @@ import io.grpc.SecurityLevel; import io.grpc.internal.GrpcAttributes; import io.grpc.internal.testing.TestUtils; -import io.grpc.netty.ProtocolNegotiators.AbstractBufferingHandler; import io.grpc.netty.ProtocolNegotiators.ClientTlsProtocolNegotiator; import io.grpc.netty.ProtocolNegotiators.HostPort; import io.grpc.netty.ProtocolNegotiators.ServerTlsHandler; @@ -45,6 +44,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerAdapter; @@ -465,7 +465,10 @@ public void httpProxy_completes() throws Exception { ProtocolNegotiator nego = ProtocolNegotiators.httpProxy(proxy, null, null, ProtocolNegotiators.plaintext()); - ChannelHandler handler = nego.newHandler(FakeGrpcHttp2ConnectionHandler.noopHandler()); + // normally NettyClientTransport will add WBAEH which kick start the ProtocolNegotiation, + // mocking the behavior using KickStartHandler. + ChannelHandler handler = + new KickStartHandler(nego.newHandler(FakeGrpcHttp2ConnectionHandler.noopHandler())); Channel channel = new Bootstrap().group(elg).channel(LocalChannel.class).handler(handler) .register().sync().channel(); pipeline = channel.pipeline(); @@ -525,7 +528,10 @@ public void httpProxy_500() throws Exception { ProtocolNegotiator nego = ProtocolNegotiators.httpProxy(proxy, null, null, ProtocolNegotiators.plaintext()); - ChannelHandler handler = nego.newHandler(FakeGrpcHttp2ConnectionHandler.noopHandler()); + // normally NettyClientTransport will add WBAEH which kick start the ProtocolNegotiation, + // mocking the behavior using KickStartHandler. + ChannelHandler handler = + new KickStartHandler(nego.newHandler(FakeGrpcHttp2ConnectionHandler.noopHandler())); Channel channel = new Bootstrap().group(elg).channel(LocalChannel.class).handler(handler) .register().sync().channel(); pipeline = channel.pipeline(); @@ -604,24 +610,6 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { elg.shutdownGracefully(); } - @Test(expected = Test.None.class /* no exception expected */) - @SuppressWarnings("TestExceptionChecker") - public void bufferingHandler_shouldNotThrowForEmptyHandler() throws Exception { - LocalAddress addr = new LocalAddress("local"); - ChannelFuture unused = new Bootstrap() - .channel(LocalChannel.class) - .handler(new BufferingHandlerWithoutHandlers()) - .group(group) - .register().sync(); - ChannelFuture sf = new ServerBootstrap() - .channel(LocalServerChannel.class) - .childHandler(new ChannelHandlerAdapter() {}) - .group(group) - .bind(addr); - // sync will trigger client's NoHandlerBufferingHandler which should not throw - sf.sync(); - } - @Test public void clientTlsHandler_firesNegotiation() throws Exception { SelfSignedCertificate cert = new SelfSignedCertificate("authority"); @@ -815,10 +803,18 @@ private static ByteBuf bb(String s, Channel c) { return ByteBufUtil.writeUtf8(c.alloc(), s); } - private static class BufferingHandlerWithoutHandlers extends AbstractBufferingHandler { + private static final class KickStartHandler extends ChannelDuplexHandler { + + private final ChannelHandler next; - public BufferingHandlerWithoutHandlers(ChannelHandler... handlers) { - super(handlers); + public KickStartHandler(ChannelHandler next) { + this.next = checkNotNull(next, "next"); + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + ctx.pipeline().replace(ctx.name(), null, next); + ctx.pipeline().fireUserEventTriggered(ProtocolNegotiationEvent.DEFAULT); } } } From fe77496f764188cc204712a79ee65006fe03fbde Mon Sep 17 00:00:00 2001 From: Srini Polavarapu <35056280+srini100@users.noreply.github.com> Date: Fri, 20 Sep 2019 16:28:42 -0700 Subject: [PATCH 022/131] Update governance, contributing, code of conduct docs (#6171) * change from Inc. to LLC for Google and update the list * Add CODE-OF-CONDUCT.md, GOVERNANCE.md and update CONTRIBUTING.md --- CODE-OF-CONDUCT.md | 3 +++ CONTRIBUTING.md | 5 ++++- GOVERNANCE.md | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 CODE-OF-CONDUCT.md create mode 100644 GOVERNANCE.md diff --git a/CODE-OF-CONDUCT.md b/CODE-OF-CONDUCT.md new file mode 100644 index 00000000000..9d4213ebca7 --- /dev/null +++ b/CODE-OF-CONDUCT.md @@ -0,0 +1,3 @@ +## Community Code of Conduct + +gRPC follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f7f45b0f01..c97ee4d3b39 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,9 @@ # How to contribute -We definitely welcome your patches and contributions to gRPC! +We definitely welcome your patches and contributions to gRPC! Please read the gRPC +organization's [governance rules](https://github.com/grpc/grpc-community/blob/master/governance.md) +and [contribution guidelines](https://github.com/grpc/grpc-community/blob/master/CONTRIBUTING.md) before proceeding. + If you are new to github, please start by reading [Pull Request howto](https://help.github.com/articles/about-pull-requests/) diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 00000000000..d6ff2674710 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1 @@ +This repository is governed by the gRPC organization's [governance rules](https://github.com/grpc/grpc-community/blob/master/governance.md). From 65321b5a6743f2089b581ab6a086ae4dffd83431 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Sun, 22 Sep 2019 16:49:09 -0700 Subject: [PATCH 023/131] xds: implement bootstrapping for xDS load balancer for alpha release (#6145) * Defined a proto message that maps the bootstrap JSON file for convenient parsing purpose. * Implemented a Bootstrapper class which reads a local bootstrap file. * Added unit test for Bootstrapper. * Let xDS load balancer bootstrap from a bootstrap file. Currently not use configurations from bootstrap in xDS communication as the xDS load balancer implementation is undergoing changes. We will integrate it later. * Added newline at the end of files. * Added json_name proto field option. * Replaced all RuntimeException with IOException for bootstrap data errors. * Changed to use JUnit exception rules in test. * Use StandardCharSets.UTF_8 * Revert "Let xDS load balancer bootstrap from a bootstrap file. Currently not use configurations from bootstrap in xDS communication as the xDS load balancer implementation is undergoing changes. We will integrate it later." This reverts commit 37200cdd3ca0926f5b1f837d7e2537387b3d4e73. * Use initialization-on-demand holder idiom for instantiating Bootstrapper instance. * Fixed usage of JUnit exception rules. * Changed lazily instantiated variable to camel case * Removed unnecessary constructor. --- xds/build.gradle | 9 +- .../main/java/io/grpc/xds/Bootstrapper.java | 133 ++++++++++++ xds/src/main/proto/bootstrap.proto | 39 ++++ .../java/io/grpc/xds/BootstrapperTest.java | 203 ++++++++++++++++++ 4 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 xds/src/main/java/io/grpc/xds/Bootstrapper.java create mode 100644 xds/src/main/proto/bootstrap.proto create mode 100644 xds/src/test/java/io/grpc/xds/BootstrapperTest.java diff --git a/xds/build.gradle b/xds/build.gradle index dd06273326f..d587af0a33f 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -20,11 +20,18 @@ dependencies { compile project(':grpc-protobuf'), project(':grpc-stub'), project(':grpc-core'), - project(':grpc-services') + project(':grpc-services'), + project(':grpc-auth') compile (libraries.protobuf_util) { // prefer 26.0-android from libraries instead of 20.0 exclude group: 'com.google.guava', module: 'guava' } + compile (libraries.google_auth_oauth2_http) { + // prefer 26.0-android from libraries instead of 25.1-android + exclude group: 'com.google.guava', module: 'guava' + // prefer 0.19.2 from libraries instead of 0.18.0 + exclude group: 'io.opencensus', module: 'opencensus-api' + } testCompile project(':grpc-core').sourceSets.test.output diff --git a/xds/src/main/java/io/grpc/xds/Bootstrapper.java b/xds/src/main/java/io/grpc/xds/Bootstrapper.java new file mode 100644 index 00000000000..e4416b386fd --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/Bootstrapper.java @@ -0,0 +1,133 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import com.google.auth.oauth2.ComputeEngineCredentials; +import com.google.common.annotations.VisibleForTesting; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.util.JsonFormat; +import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; +import io.envoyproxy.envoy.api.v2.core.ApiConfigSource.ApiType; +import io.envoyproxy.envoy.api.v2.core.Node; +import io.grpc.CallCredentials; +import io.grpc.auth.MoreCallCredentials; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import javax.annotation.concurrent.Immutable; + +/** + * Loads configuration information to bootstrap xDS load balancer. + */ +@Immutable +abstract class Bootstrapper { + + private static final String BOOTSTRAP_PATH_SYS_ENV_VAR = "GRPC_XDS_BOOTSTRAP"; + + static Bootstrapper getInstance() throws Exception { + if (FileBasedBootstrapper.defaultInstance == null) { + throw FileBasedBootstrapper.failToBootstrapException; + } + return FileBasedBootstrapper.defaultInstance; + } + + /** + * Returns the canonical name of the traffic director to be connected to. + */ + abstract String getBalancerName(); + + /** + * Returns a {@link Node} message with project/network metadata in it to be included in + * xDS requests. + */ + abstract Node getNode(); + + /** + * Returns the credentials to use when communicating with the xDS server. + */ + abstract CallCredentials getCallCredentials(); + + @VisibleForTesting + static final class FileBasedBootstrapper extends Bootstrapper { + + private static final Exception failToBootstrapException; + private static final Bootstrapper defaultInstance; + + private final String balancerName; + private final Node node; + // TODO(chengyuanzhang): Add configuration for call credentials loaded from bootstrap file. + // hard-coded for alpha release. + + static { + Bootstrapper instance = null; + Exception exception = null; + try { + instance = new FileBasedBootstrapper(Bootstrapper.readConfig()); + } catch (Exception e) { + exception = e; + } + defaultInstance = instance; + failToBootstrapException = exception; + } + + @VisibleForTesting + FileBasedBootstrapper(Bootstrap bootstrapConfig) throws IOException { + ApiConfigSource serverConfig = bootstrapConfig.getXdsServer(); + if (!serverConfig.getApiType().equals(ApiType.GRPC)) { + throw new IOException("Unexpected api type: " + serverConfig.getApiType().toString()); + } + if (serverConfig.getGrpcServicesCount() != 1) { + throw new IOException( + "Unexpected number of gRPC services: expected: 1, actual: " + + serverConfig.getGrpcServicesCount()); + } + balancerName = serverConfig.getGrpcServices(0).getGoogleGrpc().getTargetUri(); + node = bootstrapConfig.getNode(); + } + + @Override + String getBalancerName() { + return balancerName; + } + + @Override + Node getNode() { + return node; + } + + @Override + CallCredentials getCallCredentials() { + return MoreCallCredentials.from(ComputeEngineCredentials.create()); + } + } + + private static Bootstrap readConfig() throws IOException { + String filePath = System.getenv(BOOTSTRAP_PATH_SYS_ENV_VAR); + if (filePath == null) { + throw new IOException("Environment variable " + BOOTSTRAP_PATH_SYS_ENV_VAR + " not found."); + } + return parseConfig(new String(Files.readAllBytes(Paths.get(filePath)), StandardCharsets.UTF_8)); + } + + @VisibleForTesting + static Bootstrap parseConfig(String rawData) throws InvalidProtocolBufferException { + Bootstrap.Builder bootstrapBuilder = Bootstrap.newBuilder(); + JsonFormat.parser().merge(rawData, bootstrapBuilder); + return bootstrapBuilder.build(); + } +} diff --git a/xds/src/main/proto/bootstrap.proto b/xds/src/main/proto/bootstrap.proto new file mode 100644 index 00000000000..6a45a56125f --- /dev/null +++ b/xds/src/main/proto/bootstrap.proto @@ -0,0 +1,39 @@ +// Copyright 2019 The gRPC Authors +// All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. + +syntax = "proto3"; + +package io.grpc.xds; + +option java_outer_classname = "BootstrapProto"; +option java_multiple_files = true; +option java_package = "io.grpc.xds"; + +import "envoy/api/v2/core/base.proto"; +import "envoy/api/v2/core/config_source.proto"; + +// Configurations containing the information needed for xDS load balancer to bootstrap its +// communication with the xDS server. +// This proto message is defined for the convenience of parsing JSON bootstrap file in xDS load +// balancing policy only. It should not be used for any other purposes. +message Bootstrap { + // Metadata to be added to the Node message in xDS requests. + envoy.api.v2.core.Node node = 1 [json_name = "node"]; + + // Configurations including the name of the xDS server to contact, the credentials to use, etc. + envoy.api.v2.core.ApiConfigSource xds_server = 2 [json_name = "xds_server"]; +} diff --git a/xds/src/test/java/io/grpc/xds/BootstrapperTest.java b/xds/src/test/java/io/grpc/xds/BootstrapperTest.java new file mode 100644 index 00000000000..07158c9dee1 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/BootstrapperTest.java @@ -0,0 +1,203 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; +import io.envoyproxy.envoy.api.v2.core.ApiConfigSource.ApiType; +import io.envoyproxy.envoy.api.v2.core.GrpcService; +import io.envoyproxy.envoy.api.v2.core.GrpcService.GoogleGrpc; +import io.envoyproxy.envoy.api.v2.core.Locality; +import io.envoyproxy.envoy.api.v2.core.Node; +import io.grpc.xds.Bootstrapper.FileBasedBootstrapper; +import java.io.IOException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link Bootstrapper}. */ +@RunWith(JUnit4.class) +public class BootstrapperTest { + + @Rule public ExpectedException thrown = ExpectedException.none(); + + @Test + public void validBootstrap() throws IOException { + Bootstrap config = + Bootstrap.newBuilder() + .setNode( + Node.newBuilder() + .setId("ENVOY_NODE_ID") + .setLocality( + Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) + .setMetadata( + Struct.newBuilder() + .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", + Value.newBuilder().setStringValue("ENVOY_PORT").build()) + .putFields("TRAFFICDIRECTOR_NETWORK_NAME", + Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()))) + .setXdsServer(ApiConfigSource.newBuilder() + .setApiType(ApiType.GRPC) + .addGrpcServices( + GrpcService.newBuilder() + .setGoogleGrpc( + GoogleGrpc.newBuilder() + .setTargetUri("trafficdirector.googleapis.com:443").build()))) + .build(); + + Bootstrapper bootstrapper = new FileBasedBootstrapper(config); + assertThat(bootstrapper.getBalancerName()).isEqualTo("trafficdirector.googleapis.com:443"); + assertThat(bootstrapper.getNode()) + .isEqualTo( + Node.newBuilder() + .setId("ENVOY_NODE_ID") + .setLocality(Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) + .setMetadata( + Struct.newBuilder() + .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", + Value.newBuilder().setStringValue("ENVOY_PORT").build()) + .putFields("TRAFFICDIRECTOR_NETWORK_NAME", + Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()) + .build()).build()); + } + + @Test + public void unsupportedApiType() throws IOException { + Bootstrap config = + Bootstrap.newBuilder() + .setNode( + Node.newBuilder() + .setId("ENVOY_NODE_ID") + .setLocality( + Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) + .setMetadata( + Struct.newBuilder() + .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", + Value.newBuilder().setStringValue("ENVOY_PORT").build()) + .putFields("TRAFFICDIRECTOR_NETWORK_NAME", + Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()))) + .setXdsServer(ApiConfigSource.newBuilder() + .setApiType(ApiType.REST) + .addGrpcServices( + GrpcService.newBuilder() + .setGoogleGrpc( + GoogleGrpc.newBuilder() + .setTargetUri("trafficdirector.googleapis.com:443").build()))) + .build(); + + thrown.expect(IOException.class); + thrown.expectMessage("Unexpected api type: REST"); + new FileBasedBootstrapper(config); + } + + @Test + public void tooManyGrpcServices() throws IOException { + Bootstrap config = + Bootstrap.newBuilder() + .setNode( + Node.newBuilder() + .setId("ENVOY_NODE_ID") + .setLocality( + Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) + .setMetadata( + Struct.newBuilder() + .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", + Value.newBuilder().setStringValue("ENVOY_PORT").build()) + .putFields("TRAFFICDIRECTOR_NETWORK_NAME", + Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()))) + .setXdsServer(ApiConfigSource.newBuilder() + .setApiType(ApiType.GRPC) + .addGrpcServices( + GrpcService.newBuilder() + .setGoogleGrpc( + GoogleGrpc.newBuilder() + .setTargetUri("trafficdirector.googleapis.com:443").build())) + .addGrpcServices( + GrpcService.newBuilder() + .setGoogleGrpc( + GoogleGrpc.newBuilder() + .setTargetUri("foobar.googleapis.com:443").build())) + ) + .build(); + + thrown.expect(IOException.class); + thrown.expectMessage("Unexpected number of gRPC services: expected: 1, actual: 2"); + new FileBasedBootstrapper(config); + } + + @Test + public void parseBootstrap_emptyData() throws InvalidProtocolBufferException { + String rawData = ""; + + thrown.expect(InvalidProtocolBufferException.class); + Bootstrapper.parseConfig(rawData); + } + + @Test + public void parseBootstrap_invalidNodeProto() throws InvalidProtocolBufferException { + String rawData = "{" + + "\"node\": {" + + "\"id\": \"ENVOY_NODE_ID\"," + + "\"bad_field\": \"bad_value\"" + + "\"locality\": {" + + "\"zone\": \"ENVOY_ZONE\"}," + + "\"metadata\": {" + + "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", " + + "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"" + + "}" + + "}," + + "\"xds_server\": {" + + "\"api_type\": \"GRPC\"," + + "\"grpc_services\": " + + "[ {\"google_grpc\": {\"target_uri\": \"trafficdirector.googleapis.com:443\"} } ]" + + "} " + + "}"; + + thrown.expect(InvalidProtocolBufferException.class); + Bootstrapper.parseConfig(rawData); + } + + @Test + public void parseBootstrap_invalidApiConfigSourceProto() throws InvalidProtocolBufferException { + String rawData = "{" + + "\"node\": {" + + "\"id\": \"ENVOY_NODE_ID\"," + + "\"locality\": {" + + "\"zone\": \"ENVOY_ZONE\"}," + + "\"metadata\": {" + + "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", " + + "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"" + + "}" + + "}," + + "\"xds_server\": {" + + "\"api_type\": \"GRPC\"," + + "\"bad_field\": \"bad_value\"" + + "\"grpc_services\": " + + "[ {\"google_grpc\": {\"target_uri\": \"trafficdirector.googleapis.com:443\"} } ]" + + "} " + + "}"; + + thrown.expect(InvalidProtocolBufferException.class); + Bootstrapper.parseConfig(rawData); + } +} From 4db1c893f85a3ceabd3203911bb5f1c304841518 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Mon, 23 Sep 2019 11:07:24 -0700 Subject: [PATCH 024/131] xds: restructure XdsLoadBalancer Part 2: FallbackLb --- xds/src/main/java/io/grpc/xds/FallbackLb.java | 106 +++++ .../test/java/io/grpc/xds/FallbackLbTest.java | 376 ++++++++++++++++++ 2 files changed, 482 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/FallbackLb.java create mode 100644 xds/src/test/java/io/grpc/xds/FallbackLbTest.java diff --git a/xds/src/main/java/io/grpc/xds/FallbackLb.java b/xds/src/main/java/io/grpc/xds/FallbackLb.java new file mode 100644 index 00000000000..5ce0fce000f --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/FallbackLb.java @@ -0,0 +1,106 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.base.Preconditions.checkNotNull; +import static io.grpc.xds.XdsLoadBalancerProvider.XDS_POLICY_NAME; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import io.grpc.Attributes; +import io.grpc.EquivalentAddressGroup; +import io.grpc.LoadBalancer; +import io.grpc.LoadBalancerRegistry; +import io.grpc.NameResolver.ConfigOrError; +import io.grpc.Status; +import io.grpc.internal.GrpcAttributes; +import io.grpc.internal.ServiceConfigUtil.LbConfig; +import io.grpc.util.ForwardingLoadBalancer; +import io.grpc.util.GracefulSwitchLoadBalancer; +import io.grpc.xds.XdsLoadBalancerProvider.XdsConfig; +import java.util.List; +import java.util.Map; + +/** Fallback load balancer. Handles fallback policy changes. */ +final class FallbackLb extends ForwardingLoadBalancer { + + private final LoadBalancerRegistry lbRegistry; + private final GracefulSwitchLoadBalancer fallbackPolicyLb; + + FallbackLb(Helper fallbackLbHelper) { + this(fallbackLbHelper, LoadBalancerRegistry.getDefaultRegistry()); + } + + @VisibleForTesting + FallbackLb(Helper fallbackLbHelper, LoadBalancerRegistry lbRegistry) { + this.lbRegistry = lbRegistry; + fallbackPolicyLb = new GracefulSwitchLoadBalancer(fallbackLbHelper); + } + + @Override + protected LoadBalancer delegate() { + return fallbackPolicyLb; + } + + @Override + public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { + // In the future, xdsConfig can be gotten directly by + // resolvedAddresses.getLoadBalancingPolicyConfig() + Attributes attributes = resolvedAddresses.getAttributes(); + Map newRawLbConfig = checkNotNull( + attributes.get(ATTR_LOAD_BALANCING_CONFIG), "ATTR_LOAD_BALANCING_CONFIG not available"); + ConfigOrError cfg = + XdsLoadBalancerProvider.parseLoadBalancingConfigPolicy(newRawLbConfig, lbRegistry); + if (cfg.getError() != null) { + throw cfg.getError().asRuntimeException(); + } + XdsConfig xdsConfig = (XdsConfig) cfg.getConfig(); + + LbConfig fallbackPolicy = xdsConfig.fallbackPolicy; + String newFallbackPolicyName = fallbackPolicy.getPolicyName(); + fallbackPolicyLb.switchTo(lbRegistry.getProvider(newFallbackPolicyName)); + + List servers = resolvedAddresses.getAddresses(); + // Some addresses in the list may be grpclb-v1 balancer addresses, so if the fallback policy + // does not support grpclb-v1 balancer addresses, then we need to exclude them from the list. + if (!newFallbackPolicyName.equals("grpclb") && !newFallbackPolicyName.equals(XDS_POLICY_NAME)) { + ImmutableList.Builder backends = ImmutableList.builder(); + for (EquivalentAddressGroup eag : resolvedAddresses.getAddresses()) { + if (eag.getAttributes().get(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY) == null) { + backends.add(eag); + } + } + servers = backends.build(); + } + + // TODO(zhangkun83): FIXME(#5496): this is a temporary hack. + if (servers.isEmpty() + && !fallbackPolicyLb.canHandleEmptyAddressListFromNameResolution()) { + fallbackPolicyLb.handleNameResolutionError(Status.UNAVAILABLE.withDescription( + "NameResolver returned no usable address." + + " addrs=" + resolvedAddresses)); + } else { + // TODO(carl-mastrangelo): propagate the load balancing config policy + ResolvedAddresses fallbackResolvedAddresses = resolvedAddresses.toBuilder() + .setAddresses(servers) + .setAttributes(attributes.toBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, fallbackPolicy.getRawConfigValue()).build()) + .build(); + fallbackPolicyLb.handleResolvedAddresses(fallbackResolvedAddresses); + } + } +} diff --git a/xds/src/test/java/io/grpc/xds/FallbackLbTest.java b/xds/src/test/java/io/grpc/xds/FallbackLbTest.java new file mode 100644 index 00000000000..aeb54478a65 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/FallbackLbTest.java @@ -0,0 +1,376 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.truth.Truth.assertThat; +import static io.grpc.ConnectivityState.CONNECTING; +import static io.grpc.LoadBalancer.ATTR_LOAD_BALANCING_CONFIG; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.grpc.Attributes; +import io.grpc.EquivalentAddressGroup; +import io.grpc.LoadBalancer; +import io.grpc.LoadBalancer.Helper; +import io.grpc.LoadBalancer.ResolvedAddresses; +import io.grpc.LoadBalancer.SubchannelPicker; +import io.grpc.LoadBalancerProvider; +import io.grpc.LoadBalancerRegistry; +import io.grpc.Status; +import io.grpc.Status.Code; +import io.grpc.internal.GrpcAttributes; +import io.grpc.internal.JsonParser; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicReference; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; + +/** + * Tests for {@link FallbackLb}. + */ +@RunWith(JUnit4.class) +public class FallbackLbTest { + + private final LoadBalancerProvider fallbackProvider1 = new LoadBalancerProvider() { + @Override + public boolean isAvailable() { + return true; + } + + @Override + public int getPriority() { + return 5; + } + + @Override + public String getPolicyName() { + return "fallback_1"; + } + + @Override + public LoadBalancer newLoadBalancer(Helper helper) { + helpers1.add(helper); + LoadBalancer balancer = mock(LoadBalancer.class); + balancers1.add(balancer); + return balancer; + } + }; + + private final LoadBalancerProvider fallbackProvider2 = new LoadBalancerProvider() { + @Override + public boolean isAvailable() { + return true; + } + + @Override + public int getPriority() { + return 5; + } + + @Override + public String getPolicyName() { + return "fallback_2"; + } + + @Override + public LoadBalancer newLoadBalancer(Helper helper) { + // just return mock and recored helper and balancer + helpers2.add(helper); + LoadBalancer balancer = mock(LoadBalancer.class); + balancers2.add(balancer); + return balancer; + } + }; + + private final Helper helper = mock(Helper.class); + private final List helpers1 = new ArrayList<>(); + private final List helpers2 = new ArrayList<>(); + private final List balancers1 = new ArrayList<>(); + private final List balancers2 = new ArrayList<>(); + + private LoadBalancer fallbackLb; + + @Before + public void setUp() { + LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry(); + lbRegistry.register(fallbackProvider1); + lbRegistry.register(fallbackProvider2); + fallbackLb = new FallbackLb(helper, lbRegistry); + + assertThat(helpers1).isEmpty(); + assertThat(helpers2).isEmpty(); + assertThat(balancers1).isEmpty(); + assertThat(balancers2).isEmpty(); + } + + @Test + public void handlePolicyChanges() throws Exception { + EquivalentAddressGroup eag111 = new EquivalentAddressGroup(mock(SocketAddress.class)); + EquivalentAddressGroup eag112 = new EquivalentAddressGroup(mock(SocketAddress.class)); + List eags11 = ImmutableList.of(eag111, eag112); + String lbConfigRaw11 = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"fallback_1\" : { \"fallback_1_option\" : \"yes\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig11 = (Map) JsonParser.parse(lbConfigRaw11); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags11) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig11).build()) + .build()); + + assertThat(helpers1).hasSize(1); + assertThat(balancers1).hasSize(1); + Helper helper1 = helpers1.get(0); + LoadBalancer balancer1 = balancers1.get(0); + verify(balancer1).handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags11) + .setAttributes(Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("fallback_1_option", "yes")).build()) + .build()); + + SubchannelPicker picker1 = mock(SubchannelPicker.class); + helper1.updateBalancingState(CONNECTING, picker1); + verify(helper).updateBalancingState(CONNECTING, picker1); + + EquivalentAddressGroup eag121 = new EquivalentAddressGroup(mock(SocketAddress.class)); + List eags12 = ImmutableList.of(eag121); + String lbConfigRaw12 = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"fallback_1\" : { \"fallback_1_option\" : \"no\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig12 = (Map) JsonParser.parse(lbConfigRaw12); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags12) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig12).build()) + .build()); + + verify(balancer1).handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags12) + .setAttributes(Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("fallback_1_option", "no")).build()) + .build()); + + verify(balancer1, never()).shutdown(); + assertThat(helpers2).isEmpty(); + assertThat(balancers2).isEmpty(); + + // change fallback policy to fallback_2 + EquivalentAddressGroup eag211 = new EquivalentAddressGroup(mock(SocketAddress.class)); + EquivalentAddressGroup eag212 = new EquivalentAddressGroup(mock(SocketAddress.class)); + List eags21 = ImmutableList.of(eag211, eag212); + String lbConfigRaw21 = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"fallback_2\" : { \"fallback_2_option\" : \"yes\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig21 = (Map) JsonParser.parse(lbConfigRaw21); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags21) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig21).build()) + .build()); + + verify(balancer1).shutdown(); + assertThat(helpers2).hasSize(1); + assertThat(balancers2).hasSize(1); + Helper helper2 = helpers2.get(0); + LoadBalancer balancer2 = balancers2.get(0); + verify(balancer1, never()).handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags21) + .setAttributes(Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("fallback_2_option", "yes")).build()) + .build()); + verify(balancer2).handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags21) + .setAttributes(Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("fallback_2_option", "yes")).build()) + .build()); + + picker1 = mock(SubchannelPicker.class); + helper1.updateBalancingState(CONNECTING, picker1); + verify(helper, never()).updateBalancingState(CONNECTING, picker1); + SubchannelPicker picker2 = mock(SubchannelPicker.class); + helper2.updateBalancingState(CONNECTING, picker2); + verify(helper).updateBalancingState(CONNECTING, picker2); + + EquivalentAddressGroup eag221 = new EquivalentAddressGroup(mock(SocketAddress.class)); + List eags22 = ImmutableList.of(eag221); + String lbConfigRaw22 = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"fallback_2\" : { \"fallback_2_option\" : \"no\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig22 = (Map) JsonParser.parse(lbConfigRaw22); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags22) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig22).build()) + .build()); + + verify(balancer2).handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags22) + .setAttributes(Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("fallback_2_option", "no")).build()) + .build()); + + assertThat(helpers1).hasSize(1); + assertThat(balancers1).hasSize(1); + assertThat(helpers2).hasSize(1); + assertThat(balancers2).hasSize(1); + + verify(balancer2, never()).shutdown(); + fallbackLb.shutdown(); + verify(balancer2).shutdown(); + } + + + @Test + public void handleBackendsEagsOnly() throws Exception { + EquivalentAddressGroup eag0 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8080))); + Attributes attributes = Attributes + .newBuilder() + .set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "this is a balancer address") + .build(); + EquivalentAddressGroup eag1 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8081)), attributes); + EquivalentAddressGroup eag2 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8082))); + List eags = ImmutableList.of(eag0, eag1, eag2); + + String lbConfigRaw = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"fallback_1\" : { \"fallback_1_option\" : \"yes\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build()) + .build()); + + LoadBalancer balancer1 = balancers1.get(0); + verify(balancer1).handleResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of(eag0, eag2)) + .setAttributes( + Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("fallback_1_option", "yes")) + .build()) + .build()); + } + + @Test + public void resolvingWithOnlyGrpclbAddresses_NoBackendAddress() throws Exception { + Attributes attributes = Attributes + .newBuilder() + .set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "this is a balancer address") + .build(); + EquivalentAddressGroup eag1 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8081)), attributes); + EquivalentAddressGroup eag2 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8082)), attributes); + List eags = ImmutableList.of(eag1, eag2); + String lbConfigRaw = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"fallback_1\" : { \"fallback_1_option\" : \"yes\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build()) + .build()); + + LoadBalancer balancer1 = balancers1.get(0); + ArgumentCaptor statusCaptor = ArgumentCaptor.forClass(Status.class); + verify(balancer1).handleNameResolutionError(statusCaptor.capture()); + assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.UNAVAILABLE); + } + + @Test + public void handleGrpclbAddresses() throws Exception { + final AtomicReference balancer = new AtomicReference<>(); + LoadBalancerProvider grpclbProvider = new LoadBalancerProvider() { + @Override + public boolean isAvailable() { + return true; + } + + @Override + public int getPriority() { + return 5; + } + + @Override + public String getPolicyName() { + return "grpclb"; + } + + @Override + public LoadBalancer newLoadBalancer(Helper helper) { + balancer.set(mock(LoadBalancer.class)); + return balancer.get(); + } + }; + LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry(); + lbRegistry.register(grpclbProvider); + fallbackLb = new FallbackLb(helper, lbRegistry); + + EquivalentAddressGroup eag0 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8080))); + Attributes attributes = Attributes + .newBuilder() + .set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "this is a balancer address") + .build(); + EquivalentAddressGroup eag1 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8081)), attributes); + EquivalentAddressGroup eag2 = new EquivalentAddressGroup( + ImmutableList.of(new InetSocketAddress(8082))); + List eags = ImmutableList.of(eag0, eag1, eag2); + + String lbConfigRaw = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"fallbackPolicy\" : [{\"grpclb\" : { \"grpclb_option\" : \"yes\"}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); + fallbackLb.handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build()) + .build()); + + verify(balancer.get()).handleResolvedAddresses( + ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes( + Attributes.newBuilder() + .set(ATTR_LOAD_BALANCING_CONFIG, ImmutableMap.of("grpclb_option", "yes")) + .build()) + .build()); + } +} From 1f3931b3c8011ed8b05de83106bb2a2612294ebd Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Mon, 23 Sep 2019 11:07:50 -0700 Subject: [PATCH 025/131] xds: restructure XdsLoadBalancer Part 3: LookasideLb --- .../main/java/io/grpc/xds/LookasideLb.java | 115 +++++++++++++ .../java/io/grpc/xds/LookasideLbTest.java | 160 ++++++++++++++++++ 2 files changed, 275 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/LookasideLb.java create mode 100644 xds/src/test/java/io/grpc/xds/LookasideLbTest.java diff --git a/xds/src/main/java/io/grpc/xds/LookasideLb.java b/xds/src/main/java/io/grpc/xds/LookasideLb.java new file mode 100644 index 00000000000..78722a66d1a --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/LookasideLb.java @@ -0,0 +1,115 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import io.grpc.Attributes; +import io.grpc.LoadBalancer; +import io.grpc.LoadBalancerProvider; +import io.grpc.LoadBalancerRegistry; +import io.grpc.NameResolver.ConfigOrError; +import io.grpc.util.ForwardingLoadBalancer; +import io.grpc.util.GracefulSwitchLoadBalancer; +import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.XdsLoadBalancerProvider.XdsConfig; +import java.util.Map; + +/** Lookaside load balancer that handles balancer name changes. */ +final class LookasideLb extends ForwardingLoadBalancer { + + private final AdsStreamCallback adsCallback; + private final LookasideChannelLbFactory lookasideChannelLbFactory; + private final GracefulSwitchLoadBalancer lookasideChannelLb; + private final LoadBalancerRegistry lbRegistry; + + private String balancerName; + + // TODO(zdapeng): Add LookasideLb(Helper helper, AdsCallback adsCallback) with default factory + @VisibleForTesting + LookasideLb( + Helper lookasideLbHelper, + AdsStreamCallback adsCallback, + LookasideChannelLbFactory lookasideChannelLbFactory, + LoadBalancerRegistry lbRegistry) { + this.adsCallback = adsCallback; + this.lookasideChannelLbFactory = lookasideChannelLbFactory; + this.lbRegistry = lbRegistry; + this.lookasideChannelLb = new GracefulSwitchLoadBalancer(lookasideLbHelper); + } + + @Override + protected LoadBalancer delegate() { + return lookasideChannelLb; + } + + @Override + public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { + // In the future, xdsConfig can be gotten directly by + // resolvedAddresses.getLoadBalancingPolicyConfig() + Attributes attributes = resolvedAddresses.getAttributes(); + Map newRawLbConfig = checkNotNull( + attributes.get(ATTR_LOAD_BALANCING_CONFIG), "ATTR_LOAD_BALANCING_CONFIG not available"); + ConfigOrError cfg = + XdsLoadBalancerProvider.parseLoadBalancingConfigPolicy(newRawLbConfig, lbRegistry); + if (cfg.getError() != null) { + throw cfg.getError().asRuntimeException(); + } + XdsConfig xdsConfig = (XdsConfig) cfg.getConfig(); + + String newBalancerName = xdsConfig.balancerName; + if (!newBalancerName.equals(balancerName)) { + balancerName = newBalancerName; // cache the name and check next time for optimization + lookasideChannelLb.switchTo(newLookasideChannelLbProvider(newBalancerName)); + } + lookasideChannelLb.handleResolvedAddresses(resolvedAddresses); + } + + private LoadBalancerProvider newLookasideChannelLbProvider(final String balancerName) { + return new LoadBalancerProvider() { + @Override + public boolean isAvailable() { + return true; + } + + @Override + public int getPriority() { + return 5; + } + + /** + * A synthetic policy name for LookasideChannelLb identified by balancerName. The + * implementation detail doesn't matter. + */ + @Override + public String getPolicyName() { + return "xds_child_policy_balancer_name_" + balancerName; + } + + @Override + public LoadBalancer newLoadBalancer(Helper helper) { + return lookasideChannelLbFactory.newLoadBalancer(helper, adsCallback, balancerName); + } + }; + } + + @VisibleForTesting + interface LookasideChannelLbFactory { + LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback, String balancerName); + } +} diff --git a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java new file mode 100644 index 00000000000..a8a183fbd2a --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java @@ -0,0 +1,160 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.truth.Truth.assertThat; +import static io.grpc.ConnectivityState.CONNECTING; +import static io.grpc.LoadBalancer.ATTR_LOAD_BALANCING_CONFIG; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import com.google.common.collect.ImmutableList; +import io.grpc.Attributes; +import io.grpc.EquivalentAddressGroup; +import io.grpc.LoadBalancer; +import io.grpc.LoadBalancer.Helper; +import io.grpc.LoadBalancer.ResolvedAddresses; +import io.grpc.LoadBalancer.SubchannelPicker; +import io.grpc.LoadBalancerRegistry; +import io.grpc.internal.JsonParser; +import io.grpc.xds.LookasideLb.LookasideChannelLbFactory; +import io.grpc.xds.XdsComms.AdsStreamCallback; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Tests for {@link LookasideLb}. + */ +@RunWith(JUnit4.class) +public class LookasideLbTest { + + private final Helper helper = mock(Helper.class); + private final List helpers = new ArrayList<>(); + private final List balancers = new ArrayList<>(); + private final LookasideChannelLbFactory lookasideChannelLbFactory = + new LookasideChannelLbFactory() { + @Override + public LoadBalancer newLoadBalancer( + Helper helper, AdsStreamCallback adsCallback, String balancerName) { + // just return a mock and record helper and balancer. + helpers.add(helper); + LoadBalancer balancer = mock(LoadBalancer.class); + balancers.add(balancer); + return balancer; + } + }; + + private LoadBalancer lookasideLb = new LookasideLb( + helper, mock(AdsStreamCallback.class), lookasideChannelLbFactory, new LoadBalancerRegistry()); + + + @Test + public void handleChildPolicyChangeThenBalancerNameChangeThenChildPolicyChange() + throws Exception { + assertThat(helpers).isEmpty(); + assertThat(balancers).isEmpty(); + + List eags = ImmutableList.of(); + String lbConfigRaw11 = "{\"balancerName\" : \"dns:///balancer1.example.com:8080\"}"; + @SuppressWarnings("unchecked") + Map lbConfig11 = (Map) JsonParser.parse(lbConfigRaw11); + ResolvedAddresses resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig11).build()) + .build(); + lookasideLb.handleResolvedAddresses(resolvedAddresses); + + assertThat(helpers).hasSize(1); + assertThat(balancers).hasSize(1); + Helper helper1 = helpers.get(0); + LoadBalancer balancer1 = balancers.get(0); + verify(balancer1).handleResolvedAddresses(resolvedAddresses); + + SubchannelPicker picker1 = mock(SubchannelPicker.class); + helper1.updateBalancingState(CONNECTING, picker1); + verify(helper).updateBalancingState(CONNECTING, picker1); + + String lbConfigRaw12 = "{" + + "\"balancerName\" : \"dns:///balancer1.example.com:8080\"," + + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig12 = (Map) JsonParser.parse(lbConfigRaw12); + resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig12).build()) + .build(); + lookasideLb.handleResolvedAddresses(resolvedAddresses); + + verify(balancer1).handleResolvedAddresses(resolvedAddresses); + + verify(balancer1, never()).shutdown(); + assertThat(helpers).hasSize(1); + assertThat(balancers).hasSize(1); + + // change balancer name policy to balancer2.example.com + String lbConfigRaw21 = "{\"balancerName\" : \"dns:///balancer2.example.com:8080\"}"; + @SuppressWarnings("unchecked") + Map lbConfig21 = (Map) JsonParser.parse(lbConfigRaw21); + resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig21).build()) + .build(); + lookasideLb.handleResolvedAddresses(resolvedAddresses); + + verify(balancer1).shutdown(); + assertThat(helpers).hasSize(2); + assertThat(balancers).hasSize(2); + Helper helper2 = helpers.get(1); + LoadBalancer balancer2 = balancers.get(1); + verify(balancer1, never()).handleResolvedAddresses(resolvedAddresses); + verify(balancer2).handleResolvedAddresses(resolvedAddresses); + + picker1 = mock(SubchannelPicker.class); + helper1.updateBalancingState(CONNECTING, picker1); + verify(helper, never()).updateBalancingState(CONNECTING, picker1); + SubchannelPicker picker2 = mock(SubchannelPicker.class); + helper2.updateBalancingState(CONNECTING, picker2); + verify(helper).updateBalancingState(CONNECTING, picker2); + + String lbConfigRaw22 = "{" + + "\"balancerName\" : \"dns:///balancer2.example.com:8080\"," + + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]" + + "}"; + @SuppressWarnings("unchecked") + Map lbConfig22 = (Map) JsonParser.parse(lbConfigRaw22); + resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(eags) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig22).build()) + .build(); + lookasideLb.handleResolvedAddresses(resolvedAddresses); + + verify(balancer2).handleResolvedAddresses(resolvedAddresses); + + assertThat(helpers).hasSize(2); + assertThat(balancers).hasSize(2); + + verify(balancer2, never()).shutdown(); + lookasideLb.shutdown(); + verify(balancer2).shutdown(); + } +} From 2902a9373c6b149b90ceb27f622967368593bb3e Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 23 Sep 2019 11:48:00 -0700 Subject: [PATCH 026/131] gradle: Use absolute path with checkstyle fileTree The fileTree is supposed to be relative to the current project, which in this case would be the child project, but apparently it isn't. Poked around but couldn't find out why. In any case this fixes a regression introduced in 4215b80b where checkstyle would no longer file any Java files and thus it would not notice any failures. --- build.gradle | 4 ++-- xds/src/main/java/io/grpc/xds/XdsAttributes.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 884c5250c15..4db3242c5f4 100644 --- a/build.gradle +++ b/build.gradle @@ -246,11 +246,11 @@ subprojects { } checkstyleMain { - source = fileTree(dir: "src/main", include: "**/*.java") + source = fileTree(dir: "$projectDir/src/main", include: "**/*.java") } checkstyleTest { - source = fileTree(dir: "src/test", include: "**/*.java") + source = fileTree(dir: "$projectDir/src/test", include: "**/*.java") } // At a test failure, log the stack trace to the console so that we don't diff --git a/xds/src/main/java/io/grpc/xds/XdsAttributes.java b/xds/src/main/java/io/grpc/xds/XdsAttributes.java index 9d590a2f910..cca550df68a 100644 --- a/xds/src/main/java/io/grpc/xds/XdsAttributes.java +++ b/xds/src/main/java/io/grpc/xds/XdsAttributes.java @@ -21,7 +21,7 @@ import io.grpc.Grpc; /** - * Special attributes that are only useful to gRPC in the XDS context + * Special attributes that are only useful to gRPC in the XDS context. */ final class XdsAttributes { /** From cd8dbd306b043dff8b2b13100ef4a672bcf2cff7 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Mon, 23 Sep 2019 18:09:38 -0700 Subject: [PATCH 027/131] xds: use PGV dependency from maven artifact Resolves #6016 --- NOTICE.txt | 11 - build.gradle | 1 + xds/build.gradle | 6 +- xds/third_party/protoc-gen-validate/LICENSE | 202 ----- xds/third_party/protoc-gen-validate/import.sh | 52 -- .../src/main/proto/validate/validate.proto | 750 ------------------ 6 files changed, 6 insertions(+), 1016 deletions(-) delete mode 100644 xds/third_party/protoc-gen-validate/LICENSE delete mode 100755 xds/third_party/protoc-gen-validate/import.sh delete mode 100644 xds/third_party/protoc-gen-validate/src/main/proto/validate/validate.proto diff --git a/NOTICE.txt b/NOTICE.txt index 90e78fb0b1d..e8792776057 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -49,17 +49,6 @@ which can be obtained at: * LOCATION_IN_GRPC: * xds/third_party/gogoproto -This product contains a modified portion of 'protoc-gen-validate (PGV)', -an open source protoc plugin to generate polyglot message validators, -which can be obtained at: - - * LICENSE: - * xds/third_party/protoc-gen-validate/LICENSE (Apache License 2.0) - * HOMEPAGE: - * https://github.com/lyft/protoc-gen-validate - * LOCATION_IN_GRPC: - * xds/third_party/protoc-gen-validate - This product contains a modified portion of 'udpa', an open source universal data plane API, which can be obtained at: diff --git a/build.gradle b/build.gradle index 4db3242c5f4..a4dff88d0cc 100644 --- a/build.gradle +++ b/build.gradle @@ -134,6 +134,7 @@ subprojects { opencensus_impl_lite: "io.opencensus:opencensus-impl-lite:${opencensusVersion}", instrumentation_api: 'com.google.instrumentation:instrumentation-api:0.4.3', perfmark: 'io.perfmark:perfmark-api:0.17.0', + pgv: 'io.envoyproxy.protoc-gen-validate:pgv-java-stub:0.2.0', protobuf: "com.google.protobuf:protobuf-java:${protobufVersion}", protobuf_lite: "com.google.protobuf:protobuf-lite:3.0.1", protoc_lite: "com.google.protobuf:protoc-gen-javalite:3.0.0", diff --git a/xds/build.gradle b/xds/build.gradle index d587af0a33f..ce07abf6b89 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -22,6 +22,10 @@ dependencies { project(':grpc-core'), project(':grpc-services'), project(':grpc-auth') + compile (libraries.pgv) { + // PGV depends on com.google.protobuf:protobuf-java 3.6.1 conflicting with :grpc-protobuf + exclude group: 'com.google.protobuf' + } compile (libraries.protobuf_util) { // prefer 26.0-android from libraries instead of 20.0 exclude group: 'com.google.guava', module: 'guava' @@ -64,10 +68,10 @@ shadowJar { classifier = null dependencies { include(project(':grpc-xds')) + include(dependency('io.envoyproxy.protoc-gen-validate:')) } relocate 'com.github.udpa', 'io.grpc.xds.shaded.com.github.udpa' relocate 'io.envoyproxy', 'io.grpc.xds.shaded.io.envoyproxy' - relocate 'validate', 'io.grpc.xds.shaded.com.lyft.pgv.validate' exclude "**/*.proto" } diff --git a/xds/third_party/protoc-gen-validate/LICENSE b/xds/third_party/protoc-gen-validate/LICENSE deleted file mode 100644 index d6456956733..00000000000 --- a/xds/third_party/protoc-gen-validate/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/xds/third_party/protoc-gen-validate/import.sh b/xds/third_party/protoc-gen-validate/import.sh deleted file mode 100755 index dd37b91cb11..00000000000 --- a/xds/third_party/protoc-gen-validate/import.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -# Copyright 2018 The gRPC Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Update GIT_ORIGIN_REV_ID then in this directory run ./import.sh - -set -e -BRANCH=master -# import GIT_ORIGIN_REV_ID from one of the google internal CLs -GIT_ORIGIN_REV_ID=8e6aaf55f4954f1ef9d3ee2e8f5a50e79cc04f8f -GIT_REPO="https://github.com/lyft/protoc-gen-validate.git" -GIT_BASE_DIR=protoc-gen-validate -SOURCE_PROTO_BASE_DIR=protoc-gen-validate -TARGET_PROTO_BASE_DIR=src/main/proto -FILES=( -validate/validate.proto -) - -# clone the protoc-gen-validate github repo in a tmp directory -tmpdir="$(mktemp -d)" -pushd "${tmpdir}" -rm -rf "$GIT_BASE_DIR" -git clone -b $BRANCH $GIT_REPO -cd "$GIT_BASE_DIR" -git checkout $GIT_ORIGIN_REV_ID -popd - -cp -p "${tmpdir}/${GIT_BASE_DIR}/LICENSE" LICENSE - -mkdir -p "${TARGET_PROTO_BASE_DIR}" -pushd "${TARGET_PROTO_BASE_DIR}" - -# copy proto files to project directory -for file in "${FILES[@]}" -do - mkdir -p "$(dirname "${file}")" - cp -p "${tmpdir}/${SOURCE_PROTO_BASE_DIR}/${file}" "${file}" -done -popd - -rm -rf "$tmpdir" diff --git a/xds/third_party/protoc-gen-validate/src/main/proto/validate/validate.proto b/xds/third_party/protoc-gen-validate/src/main/proto/validate/validate.proto deleted file mode 100644 index 5d5d96d9ed3..00000000000 --- a/xds/third_party/protoc-gen-validate/src/main/proto/validate/validate.proto +++ /dev/null @@ -1,750 +0,0 @@ -syntax = "proto2"; -package validate; - -option go_package = "github.com/lyft/protoc-gen-validate/validate"; - -import "google/protobuf/descriptor.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/timestamp.proto"; - -// Validation rules applied at the message level -extend google.protobuf.MessageOptions { - // Disabled nullifies any validation rules for this message, including any - // message fields associated with it that do support validation. - optional bool disabled = 919191; -} - -// Validation rules applied at the oneof level -extend google.protobuf.OneofOptions { - // Required ensures that exactly one the field options in a oneof is set; - // validation fails if no fields in the oneof are set. - optional bool required = 919191; -} - -// Validation rules applied at the field level -extend google.protobuf.FieldOptions { - // Rules specify the validations to be performed on this field. By default, - // no validation is performed against a field. - optional FieldRules rules = 919191; -} - -// FieldRules encapsulates the rules for each type of field. Depending on the -// field, the correct set should be used to ensure proper validations. -message FieldRules { - oneof type { - // Scalar Field Types - FloatRules float = 1; - DoubleRules double = 2; - Int32Rules int32 = 3; - Int64Rules int64 = 4; - UInt32Rules uint32 = 5; - UInt64Rules uint64 = 6; - SInt32Rules sint32 = 7; - SInt64Rules sint64 = 8; - Fixed32Rules fixed32 = 9; - Fixed64Rules fixed64 = 10; - SFixed32Rules sfixed32 = 11; - SFixed64Rules sfixed64 = 12; - BoolRules bool = 13; - StringRules string = 14; - BytesRules bytes = 15; - - // Complex Field Types - EnumRules enum = 16; - MessageRules message = 17; - RepeatedRules repeated = 18; - MapRules map = 19; - - // Well-Known Field Types - AnyRules any = 20; - DurationRules duration = 21; - TimestampRules timestamp = 22; - } -} - -// FloatRules describes the constraints applied to `float` values -message FloatRules { - // Const specifies that this field must be exactly the specified value - optional float const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional float lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional float lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional float gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional float gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated float in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated float not_in = 7; -} - -// DoubleRules describes the constraints applied to `double` values -message DoubleRules { - // Const specifies that this field must be exactly the specified value - optional double const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional double lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional double lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional double gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional double gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated double in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated double not_in = 7; -} - -// Int32Rules describes the constraints applied to `int32` values -message Int32Rules { - // Const specifies that this field must be exactly the specified value - optional int32 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional int32 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional int32 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional int32 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional int32 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated int32 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated int32 not_in = 7; -} - -// Int64Rules describes the constraints applied to `int64` values -message Int64Rules { - // Const specifies that this field must be exactly the specified value - optional int64 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional int64 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional int64 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional int64 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional int64 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated int64 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated int64 not_in = 7; -} - -// UInt32Rules describes the constraints applied to `uint32` values -message UInt32Rules { - // Const specifies that this field must be exactly the specified value - optional uint32 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional uint32 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional uint32 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional uint32 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional uint32 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated uint32 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated uint32 not_in = 7; -} - -// UInt64Rules describes the constraints applied to `uint64` values -message UInt64Rules { - // Const specifies that this field must be exactly the specified value - optional uint64 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional uint64 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional uint64 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional uint64 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional uint64 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated uint64 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated uint64 not_in = 7; -} - -// SInt32Rules describes the constraints applied to `sint32` values -message SInt32Rules { - // Const specifies that this field must be exactly the specified value - optional sint32 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional sint32 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional sint32 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional sint32 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional sint32 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated sint32 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated sint32 not_in = 7; -} - -// SInt64Rules describes the constraints applied to `sint64` values -message SInt64Rules { - // Const specifies that this field must be exactly the specified value - optional sint64 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional sint64 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional sint64 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional sint64 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional sint64 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated sint64 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated sint64 not_in = 7; -} - -// Fixed32Rules describes the constraints applied to `fixed32` values -message Fixed32Rules { - // Const specifies that this field must be exactly the specified value - optional fixed32 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional fixed32 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional fixed32 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional fixed32 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional fixed32 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated fixed32 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated fixed32 not_in = 7; -} - -// Fixed64Rules describes the constraints applied to `fixed64` values -message Fixed64Rules { - // Const specifies that this field must be exactly the specified value - optional fixed64 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional fixed64 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional fixed64 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional fixed64 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional fixed64 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated fixed64 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated fixed64 not_in = 7; -} - -// SFixed32Rules describes the constraints applied to `sfixed32` values -message SFixed32Rules { - // Const specifies that this field must be exactly the specified value - optional sfixed32 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional sfixed32 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional sfixed32 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional sfixed32 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional sfixed32 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated sfixed32 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated sfixed32 not_in = 7; -} - -// SFixed64Rules describes the constraints applied to `sfixed64` values -message SFixed64Rules { - // Const specifies that this field must be exactly the specified value - optional sfixed64 const = 1; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional sfixed64 lt = 2; - - // Lte specifies that this field must be less than or equal to the - // specified value, inclusive - optional sfixed64 lte = 3; - - // Gt specifies that this field must be greater than the specified value, - // exclusive. If the value of Gt is larger than a specified Lt or Lte, the - // range is reversed. - optional sfixed64 gt = 4; - - // Gte specifies that this field must be greater than or equal to the - // specified value, inclusive. If the value of Gte is larger than a - // specified Lt or Lte, the range is reversed. - optional sfixed64 gte = 5; - - // In specifies that this field must be equal to one of the specified - // values - repeated sfixed64 in = 6; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated sfixed64 not_in = 7; -} - -// BoolRules describes the constraints applied to `bool` values -message BoolRules { - // Const specifies that this field must be exactly the specified value - optional bool const = 1; -} - -// StringRules describe the constraints applied to `string` values -message StringRules { - // Const specifies that this field must be exactly the specified value - optional string const = 1; - - // MinLen specifies that this field must be the specified number of - // characters (Unicode code points) at a minimum. Note that the number of - // characters may differ from the number of bytes in the string. - optional uint64 min_len = 2; - - // MaxLen specifies that this field must be the specified number of - // characters (Unicode code points) at a maximum. Note that the number of - // characters may differ from the number of bytes in the string. - optional uint64 max_len = 3; - - // MinBytes specifies that this field must be the specified number of bytes - // at a minimum - optional uint64 min_bytes = 4; - - // MaxBytes specifies that this field must be the specified number of bytes - // at a maximum - optional uint64 max_bytes = 5; - - // Pattern specifes that this field must match against the specified - // regular expression (RE2 syntax). The included expression should elide - // any delimiters. - optional string pattern = 6; - - // Prefix specifies that this field must have the specified substring at - // the beginning of the string. - optional string prefix = 7; - - // Suffix specifies that this field must have the specified substring at - // the end of the string. - optional string suffix = 8; - - // Contains specifies that this field must have the specified substring - // anywhere in the string. - optional string contains = 9; - - // In specifies that this field must be equal to one of the specified - // values - repeated string in = 10; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated string not_in = 11; - - // WellKnown rules provide advanced constraints against common string - // patterns - oneof well_known { - // Email specifies that the field must be a valid email address as - // defined by RFC 5322 - bool email = 12; - - // Hostname specifies that the field must be a valid hostname as - // defined by RFC 1034. This constraint does not support - // internationalized domain names (IDNs). - bool hostname = 13; - - // Ip specifies that the field must be a valid IP (v4 or v6) address. - // Valid IPv6 addresses should not include surrounding square brackets. - bool ip = 14; - - // Ipv4 specifies that the field must be a valid IPv4 address. - bool ipv4 = 15; - - // Ipv6 specifies that the field must be a valid IPv6 address. Valid - // IPv6 addresses should not include surrounding square brackets. - bool ipv6 = 16; - - // Uri specifies that the field must be a valid, absolute URI as defined - // by RFC 3986 - bool uri = 17; - - // UriRef specifies that the field must be a valid URI as defined by RFC - // 3986 and may be relative or absolute. - bool uri_ref = 18; - } -} - -// BytesRules describe the constraints applied to `bytes` values -message BytesRules { - // Const specifies that this field must be exactly the specified value - optional bytes const = 1; - - // MinLen specifies that this field must be the specified number of bytes - // at a minimum - optional uint64 min_len = 2; - - // MaxLen specifies that this field must be the specified number of bytes - // at a maximum - optional uint64 max_len = 3; - - // Pattern specifes that this field must match against the specified - // regular expression (RE2 syntax). The included expression should elide - // any delimiters. - optional string pattern = 4; - - // Prefix specifies that this field must have the specified bytes at the - // beginning of the string. - optional bytes prefix = 5; - - // Suffix specifies that this field must have the specified bytes at the - // end of the string. - optional bytes suffix = 6; - - // Contains specifies that this field must have the specified bytes - // anywhere in the string. - optional bytes contains = 7; - - // In specifies that this field must be equal to one of the specified - // values - repeated bytes in = 8; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated bytes not_in = 9; - - // WellKnown rules provide advanced constraints against common byte - // patterns - oneof well_known { - // Ip specifies that the field must be a valid IP (v4 or v6) address in - // byte format - bool ip = 10; - - // Ipv4 specifies that the field must be a valid IPv4 address in byte - // format - bool ipv4 = 11; - - // Ipv6 specifies that the field must be a valid IPv6 address in byte - // format - bool ipv6 = 12; - } -} - -// EnumRules describe the constraints applied to enum values -message EnumRules { - // Const specifies that this field must be exactly the specified value - optional int32 const = 1; - - // DefinedOnly specifies that this field must be only one of the defined - // values for this enum, failing on any undefined value. - optional bool defined_only = 2; - - // In specifies that this field must be equal to one of the specified - // values - repeated int32 in = 3; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated int32 not_in = 4; -} - -// MessageRules describe the constraints applied to embedded message values. -// For message-type fields, validation is performed recursively. -message MessageRules { - // Skip specifies that the validation rules of this field should not be - // evaluated - optional bool skip = 1; - - // Required specifies that this field must be set - optional bool required = 2; -} - -// RepeatedRules describe the constraints applied to `repeated` values -message RepeatedRules { - // MinItems specifies that this field must have the specified number of - // items at a minimum - optional uint64 min_items = 1; - - // MaxItems specifies that this field must have the specified number of - // items at a maximum - optional uint64 max_items = 2; - - // Unique specifies that all elements in this field must be unique. This - // contraint is only applicable to scalar and enum types (messages are not - // supported). - optional bool unique = 3; - - // Items specifies the contraints to be applied to each item in the field. - // Repeated message fields will still execute validation against each item - // unless skip is specified here. - optional FieldRules items = 4; -} - -// MapRules describe the constraints applied to `map` values -message MapRules { - // MinPairs specifies that this field must have the specified number of - // KVs at a minimum - optional uint64 min_pairs = 1; - - // MaxPairs specifies that this field must have the specified number of - // KVs at a maximum - optional uint64 max_pairs = 2; - - // NoSparse specifies values in this field cannot be unset. This only - // applies to map's with message value types. - optional bool no_sparse = 3; - - // Keys specifies the constraints to be applied to each key in the field. - optional FieldRules keys = 4; - - // Values specifies the constraints to be applied to the value of each key - // in the field. Message values will still have their validations evaluated - // unless skip is specified here. - optional FieldRules values = 5; -} - -// AnyRules describe constraints applied exclusively to the -// `google.protobuf.Any` well-known type -message AnyRules { - // Required specifies that this field must be set - optional bool required = 1; - - // In specifies that this field's `type_url` must be equal to one of the - // specified values. - repeated string in = 2; - - // NotIn specifies that this field's `type_url` must not be equal to any of - // the specified values. - repeated string not_in = 3; -} - -// DurationRules describe the constraints applied exclusively to the -// `google.protobuf.Duration` well-known type -message DurationRules { - // Required specifies that this field must be set - optional bool required = 1; - - // Const specifies that this field must be exactly the specified value - optional google.protobuf.Duration const = 2; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional google.protobuf.Duration lt = 3; - - // Lt specifies that this field must be less than the specified value, - // inclusive - optional google.protobuf.Duration lte = 4; - - // Gt specifies that this field must be greater than the specified value, - // exclusive - optional google.protobuf.Duration gt = 5; - - // Gte specifies that this field must be greater than the specified value, - // inclusive - optional google.protobuf.Duration gte = 6; - - // In specifies that this field must be equal to one of the specified - // values - repeated google.protobuf.Duration in = 7; - - // NotIn specifies that this field cannot be equal to one of the specified - // values - repeated google.protobuf.Duration not_in = 8; -} - -// TimestampRules describe the constraints applied exclusively to the -// `google.protobuf.Timestamp` well-known type -message TimestampRules { - // Required specifies that this field must be set - optional bool required = 1; - - // Const specifies that this field must be exactly the specified value - optional google.protobuf.Timestamp const = 2; - - // Lt specifies that this field must be less than the specified value, - // exclusive - optional google.protobuf.Timestamp lt = 3; - - // Lte specifies that this field must be less than the specified value, - // inclusive - optional google.protobuf.Timestamp lte = 4; - - // Gt specifies that this field must be greater than the specified value, - // exclusive - optional google.protobuf.Timestamp gt = 5; - - // Gte specifies that this field must be greater than the specified value, - // inclusive - optional google.protobuf.Timestamp gte = 6; - - // LtNow specifies that this must be less than the current time. LtNow - // can only be used with the Within rule. - optional bool lt_now = 7; - - // GtNow specifies that this must be greater than the current time. GtNow - // can only be used with the Within rule. - optional bool gt_now = 8; - - // Within specifies that this field must be within this duration of the - // current time. This constraint can be used alone or with the LtNow and - // GtNow rules. - optional google.protobuf.Duration within = 9; -} From 5bc1309c87912b0b72a29add834ad8937291df09 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Mon, 23 Sep 2019 18:32:43 -0700 Subject: [PATCH 028/131] xds: Priority failover - Implementing priority failover - Removed `localityWeight` field from `LocalityLbInfo` because this is always available and up to date in `edsResponsLocalityInfo`, otherwise need to create a new instance of `LocalityLbInfo` each time weight is updated. - Introduced `PriorityManager` that manages all the priority failover logic. --- .../main/java/io/grpc/xds/LocalityStore.java | 315 +++++++---- xds/src/main/java/io/grpc/xds/XdsComms.java | 21 +- .../java/io/grpc/xds/LocalityStoreTest.java | 509 ++++++++++++++++-- .../test/java/io/grpc/xds/XdsCommsTest.java | 14 +- .../java/io/grpc/xds/XdsLoadBalancerTest.java | 24 +- 5 files changed, 710 insertions(+), 173 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/LocalityStore.java b/xds/src/main/java/io/grpc/xds/LocalityStore.java index def3b99a06b..f8d3c8ad18a 100644 --- a/xds/src/main/java/io/grpc/xds/LocalityStore.java +++ b/xds/src/main/java/io/grpc/xds/LocalityStore.java @@ -16,7 +16,6 @@ package io.grpc.xds; -import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static io.grpc.ConnectivityState.CONNECTING; import static io.grpc.ConnectivityState.IDLE; @@ -27,9 +26,9 @@ import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import io.grpc.ConnectivityState; import io.grpc.ConnectivityStateInfo; -import io.grpc.EquivalentAddressGroup; import io.grpc.LoadBalancer; import io.grpc.LoadBalancer.Helper; import io.grpc.LoadBalancer.PickResult; @@ -53,8 +52,8 @@ import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -70,7 +69,7 @@ interface LocalityStore { void reset(); - void updateLocalityStore(Map localityInfoMap); + void updateLocalityStore(ImmutableMap localityInfoMap); void updateDropPercentage(ImmutableList dropOverloads); @@ -91,9 +90,10 @@ final class LocalityStoreImpl implements LocalityStore { private final LoadStatsStore loadStatsStore; private final OrcaPerRequestUtil orcaPerRequestUtil; private final OrcaOobUtil orcaOobUtil; - - private final Map localityMap = new LinkedHashMap<>(); - private Map edsResponsLocalityInfo = ImmutableMap.of(); + private final PriorityManager priorityManager = new PriorityManager(); + private final Map localityMap = new HashMap<>(); + // Most current set of localities instructed by traffic director + private Set localities = ImmutableSet.of(); private ImmutableList dropOverloads = ImmutableList.of(); private long metricsReportIntervalNano = -1; @@ -189,90 +189,50 @@ public void reset() { localityMap.get(locality).shutdown(); } localityMap.clear(); - for (XdsLocality locality : edsResponsLocalityInfo.keySet()) { + + for (XdsLocality locality : localities) { loadStatsStore.removeLocality(locality); } - edsResponsLocalityInfo = ImmutableMap.of(); + localities = ImmutableSet.of(); + + priorityManager.reset(); } // This is triggered by EDS response. @Override - public void updateLocalityStore(Map localityInfoMap) { - Set oldLocalities = localityMap.keySet(); - Set newLocalities = localityInfoMap.keySet(); - Map updatedLocalityMap = new LinkedHashMap<>(); + public void updateLocalityStore(final ImmutableMap localityInfoMap) { - for (XdsLocality oldLocality : oldLocalities) { - if (!newLocalities.contains(oldLocality)) { - deactivate(oldLocality); + Set newLocalities = localityInfoMap.keySet(); + // TODO: put endPointWeights into attributes for WRR. + for (XdsLocality locality : newLocalities) { + if (localityMap.containsKey(locality)) { + final LocalityLbInfo localityLbInfo = localityMap.get(locality); + final LocalityInfo localityInfo = localityInfoMap.get(locality); + // In extreme case handleResolvedAddresses() may trigger updateBalancingState() + // immediately, so execute handleResolvedAddresses() after all the setup in this method is + // complete. + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + localityLbInfo.childBalancer.handleResolvedAddresses( + ResolvedAddresses.newBuilder().setAddresses(localityInfo.eags).build()); + } + }); } } for (XdsLocality newLocality : newLocalities) { - - if (!edsResponsLocalityInfo.containsKey(newLocality)) { + if (!localities.contains(newLocality)) { loadStatsStore.addLocality(newLocality); } - - // Assuming standard mode only (EDS response with a list of endpoints) for now. - final List newEags = localityInfoMap.get(newLocality).eags; - final LocalityLbInfo localityLbInfo; - ChildHelper childHelper; - if (oldLocalities.contains(newLocality)) { - LocalityLbInfo oldLocalityLbInfo = localityMap.get(newLocality); - - oldLocalityLbInfo.reactivate(); - - childHelper = oldLocalityLbInfo.childHelper; - localityLbInfo = - new LocalityLbInfo( - localityInfoMap.get(newLocality).localityWeight, - oldLocalityLbInfo.childBalancer, - childHelper); - } else { - childHelper = - new ChildHelper(newLocality, loadStatsStore.getLocalityCounter(newLocality), - orcaOobUtil); - localityLbInfo = - new LocalityLbInfo( - localityInfoMap.get(newLocality).localityWeight, - loadBalancerProvider.newLoadBalancer(childHelper), - childHelper); - if (metricsReportIntervalNano > 0) { - localityLbInfo.childHelper.updateMetricsReportInterval(metricsReportIntervalNano); - } - } - updatedLocalityMap.put(newLocality, localityLbInfo); - - // In extreme case handleResolvedAddresses() may trigger updateBalancingState() immediately, - // so execute handleResolvedAddresses() after all the setup in this method is complete. - helper.getSynchronizationContext().execute(new Runnable() { - @Override - public void run() { - // TODO: put endPointWeights into attributes for WRR. - localityLbInfo.childBalancer - .handleResolvedAddresses( - ResolvedAddresses.newBuilder().setAddresses(newEags).build()); - } - }); - } - - // Add deactivated localities to localityMap to keep track of them. - for (XdsLocality locality : oldLocalities) { - if (localityMap.get(locality).isDeactivated()) { - updatedLocalityMap.put(locality, localityMap.get(locality)); - } } - localityMap.clear(); - localityMap.putAll(updatedLocalityMap); - final Set toBeRemovedFromStatsStore = new HashSet<>(); // There is a race between picking a subchannel and updating localities, which leads to // the possibility that RPCs will be sent to a removed locality. As a result, those RPC // loads will not be recorded. We consider this to be natural. By removing locality counters // after updating subchannel pickers, we eliminate the race and conservatively record loads // happening in that period. - for (XdsLocality oldLocality : edsResponsLocalityInfo.keySet()) { + for (XdsLocality oldLocality : localities) { if (!localityInfoMap.containsKey(oldLocality)) { toBeRemovedFromStatsStore.add(oldLocality); } @@ -285,9 +245,15 @@ public void run() { } } }); + localities = newLocalities; + + priorityManager.updateLocalities(localityInfoMap); - edsResponsLocalityInfo = ImmutableMap.copyOf(localityInfoMap); - onChildStateUpdated(); + for (XdsLocality oldLocality : localityMap.keySet()) { + if (!newLocalities.contains(oldLocality)) { + deactivate(oldLocality); + } + } } @Override @@ -308,13 +274,16 @@ public void run() { localityLbInfo.shutdown(); localityMap.remove(locality); } + + @Override + public String toString() { + return "DeletionTask: locality=" + locality; + } } localityLbInfo.delayedDeletionTimer = helper.getSynchronizationContext().schedule( new DeletionTask(), DELAYED_DELETION_TIMEOUT_MINUTES, TimeUnit.MINUTES, helper.getScheduledExecutorService()); - - onChildStateUpdated(); } @Override @@ -348,29 +317,6 @@ private static ConnectivityState aggregateState( return overallState; } - private void onChildStateUpdated() { - List childPickers = new ArrayList<>(); - - ConnectivityState overallState = null; - for (XdsLocality l : localityMap.keySet()) { - if (localityMap.get(l).isDeactivated()) { - continue; - } - LocalityLbInfo localityLbInfo = localityMap.get(l); - ConnectivityState childState = localityLbInfo.childHelper.currentChildState; - SubchannelPicker childPicker = localityLbInfo.childHelper.currentChildPicker; - - overallState = aggregateState(overallState, childState); - - if (READY == childState) { - childPickers.add( - new WeightedChildPicker(localityLbInfo.localityWeight, childPicker)); - } - } - - updatePicker(overallState, childPickers); - } - private void updatePicker( @Nullable ConnectivityState state, List childPickers) { childPickers = Collections.unmodifiableList(childPickers); @@ -397,9 +343,9 @@ private void updatePicker( /** * State of a single Locality. */ + // TODO(zdapeng): rename it to LocalityLbState static final class LocalityLbInfo { - final int localityWeight; final LoadBalancer childBalancer; final ChildHelper childHelper; @@ -407,9 +353,7 @@ static final class LocalityLbInfo { private ScheduledHandle delayedDeletionTimer; LocalityLbInfo( - int localityWeight, LoadBalancer childBalancer, ChildHelper childHelper) { - checkArgument(localityWeight >= 0, "localityWeight must be non-negative"); - this.localityWeight = localityWeight; + LoadBalancer childBalancer, ChildHelper childHelper) { this.childBalancer = checkNotNull(childBalancer, "childBalancer"); this.childHelper = checkNotNull(childHelper, "childHelper"); } @@ -426,8 +370,6 @@ void reactivate() { if (delayedDeletionTimer != null) { delayedDeletionTimer.cancel(); delayedDeletionTimer = null; - childHelper.updateBalancingState( - childHelper.currentChildState, childHelper.currentChildPicker); } } @@ -467,7 +409,7 @@ public void updateBalancingState(ConnectivityState newState, newPicker, orcaPerRequestUtil)); // delegate to parent helper - onChildStateUpdated(); + priorityManager.updatePriorityState(priorityManager.getPriority(locality)); } @Override @@ -484,6 +426,10 @@ public String getAuthority() { orcaReportingHelperWrapper = checkNotNull(orcaOobUtil, "orcaOobUtil") .newOrcaReportingHelperWrapper(delegate, new MetricsRecordingListener(counter)); + + if (metricsReportIntervalNano > 0) { + updateMetricsReportInterval(metricsReportIntervalNano); + } } void updateMetricsReportInterval(long intervalNanos) { @@ -497,5 +443,164 @@ protected Helper delegate() { return orcaReportingHelperWrapper.asHelper(); } } + + private final class PriorityManager { + + private final List> priorityTable = new ArrayList<>(); + private Map localityInfoMap = ImmutableMap.of(); + private int currentPriority = -1; + private ScheduledHandle failOverTimer; + + /** + * Updates the priority ordering of localities with the given collection of localities. + * Recomputes the current ready localities to be used. + */ + void updateLocalities(Map localityInfoMap) { + this.localityInfoMap = localityInfoMap; + priorityTable.clear(); + for (XdsLocality newLocality : localityInfoMap.keySet()) { + int priority = localityInfoMap.get(newLocality).priority; + while (priorityTable.size() <= priority) { + priorityTable.add(new ArrayList()); + } + priorityTable.get(priority).add(newLocality); + } + + currentPriority = -1; + failOver(); + } + + /** + * Refreshes the group of localities with the given priority. Recomputes the current ready + * localities to be used. + */ + void updatePriorityState(int priority) { + if (priority == -1 || priority > currentPriority) { + return; + } + List childPickers = new ArrayList<>(); + + ConnectivityState overallState = null; + for (XdsLocality l : priorityTable.get(priority)) { + if (!localityMap.containsKey(l)) { + initLocality(l); + } + LocalityLbInfo localityLbInfo = localityMap.get(l); + localityLbInfo.reactivate(); + ConnectivityState childState = localityLbInfo.childHelper.currentChildState; + SubchannelPicker childPicker = localityLbInfo.childHelper.currentChildPicker; + + overallState = aggregateState(overallState, childState); + + if (READY == childState) { + childPickers.add( + new WeightedChildPicker(localityInfoMap.get(l).localityWeight, childPicker)); + } + } + + if (priority == currentPriority) { + updatePicker(overallState, childPickers); + if (overallState == READY) { + cancelFailOverTimer(); + } else if (overallState == TRANSIENT_FAILURE) { + cancelFailOverTimer(); + failOver(); + } else if (failOverTimer == null) { + failOver(); + } // else, still connecting and failOverTimer not expired yet, noop + } else if (overallState == READY) { + updatePicker(overallState, childPickers); + cancelFailOverTimer(); + currentPriority = priority; + } + + if (overallState == READY) { + for (int p = priority + 1; p < priorityTable.size(); p++) { + for (XdsLocality xdsLocality : priorityTable.get(p)) { + deactivate(xdsLocality); + } + } + } + } + + int getPriority(XdsLocality locality) { + if (localityInfoMap.containsKey(locality)) { + return localityInfoMap.get(locality).priority; + } + return -1; + } + + void reset() { + cancelFailOverTimer(); + priorityTable.clear(); + localityInfoMap = ImmutableMap.of(); + currentPriority = -1; + } + + private void cancelFailOverTimer() { + if (failOverTimer != null) { + failOverTimer.cancel(); + failOverTimer = null; + } + } + + private void failOver() { + if (currentPriority == priorityTable.size() - 1) { + return; + } + + currentPriority++; + + List localities = priorityTable.get(currentPriority); + boolean initializedBefore = false; + for (XdsLocality locality : localities) { + if (localityMap.containsKey(locality)) { + initializedBefore = true; + localityMap.get(locality).reactivate(); + } else { + initLocality(locality); + } + } + + if (!initializedBefore) { + class FailOverTask implements Runnable { + @Override + public void run() { + failOverTimer = null; + failOver(); + } + } + + failOverTimer = helper.getSynchronizationContext().schedule( + new FailOverTask(), 10, TimeUnit.SECONDS, helper.getScheduledExecutorService()); + } + + updatePriorityState(currentPriority); + } + + private void initLocality(final XdsLocality locality) { + ChildHelper childHelper = + new ChildHelper(locality, loadStatsStore.getLocalityCounter(locality), + orcaOobUtil); + final LocalityLbInfo localityLbInfo = + new LocalityLbInfo( + loadBalancerProvider.newLoadBalancer(childHelper), + childHelper); + localityMap.put(locality, localityLbInfo); + + final LocalityInfo localityInfo = localityInfoMap.get(locality); + // In extreme case handleResolvedAddresses() may trigger updateBalancingState() immediately, + // so execute handleResolvedAddresses() after all the setup in the caller is complete. + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + // TODO: put endPointWeights into attributes for WRR. + localityLbInfo.childBalancer + .handleResolvedAddresses(ResolvedAddresses.newBuilder() + .setAddresses(localityInfo.eags).build()); + } + }); + } + } } } diff --git a/xds/src/main/java/io/grpc/xds/XdsComms.java b/xds/src/main/java/io/grpc/xds/XdsComms.java index b41cf177461..ca5f1b44544 100644 --- a/xds/src/main/java/io/grpc/xds/XdsComms.java +++ b/xds/src/main/java/io/grpc/xds/XdsComms.java @@ -26,6 +26,7 @@ import com.google.common.base.Stopwatch; import com.google.common.base.Supplier; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Struct; import com.google.protobuf.Value; @@ -50,9 +51,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; -import java.util.Map; import java.util.concurrent.TimeUnit; import javax.annotation.CheckForNull; @@ -76,12 +75,14 @@ final class XdsComms { /** * Information about the locality from EDS response. */ + // TODO(zdapeng): move this class out. static final class LocalityInfo { final List eags; final List endPointWeights; final int localityWeight; + final int priority; - LocalityInfo(Collection lbEndPoints, int localityWeight) { + LocalityInfo(Collection lbEndPoints, int localityWeight, int priority) { List eags = new ArrayList<>(lbEndPoints.size()); List endPointWeights = new ArrayList<>(lbEndPoints.size()); for (LbEndpoint lbEndPoint : lbEndPoints) { @@ -91,6 +92,7 @@ static final class LocalityInfo { this.eags = Collections.unmodifiableList(eags); this.endPointWeights = Collections.unmodifiableList(new ArrayList<>(endPointWeights)); this.localityWeight = localityWeight; + this.priority = priority; } @Override @@ -103,13 +105,14 @@ public boolean equals(Object o) { } LocalityInfo that = (LocalityInfo) o; return localityWeight == that.localityWeight + && priority == that.priority && Objects.equal(eags, that.eags) && Objects.equal(endPointWeights, that.endPointWeights); } @Override public int hashCode() { - return Objects.hashCode(eags, endPointWeights, localityWeight); + return Objects.hashCode(eags, endPointWeights, localityWeight, priority); } } @@ -239,7 +242,8 @@ public void run() { localityStore.updateDropPercentage(dropOverloads); List localities = clusterLoadAssignment.getEndpointsList(); - Map localityEndpointsMapping = new LinkedHashMap<>(); + ImmutableMap.Builder localityEndpointsMapping = + new ImmutableMap.Builder<>(); for (LocalityLbEndpoints localityLbEndpoints : localities) { io.envoyproxy.envoy.api.v2.core.Locality localityProto = localityLbEndpoints.getLocality(); @@ -250,16 +254,15 @@ public void run() { lbEndPoints.add(new LbEndpoint(lbEndpoint)); } int localityWeight = localityLbEndpoints.getLoadBalancingWeight().getValue(); + int priority = localityLbEndpoints.getPriority(); if (localityWeight != 0) { localityEndpointsMapping.put( - locality, new LocalityInfo(lbEndPoints, localityWeight)); + locality, new LocalityInfo(lbEndPoints, localityWeight, priority)); } } - localityEndpointsMapping = Collections.unmodifiableMap(localityEndpointsMapping); - - localityStore.updateLocalityStore(localityEndpointsMapping); + localityStore.updateLocalityStore(localityEndpointsMapping.build()); } } } diff --git a/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java b/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java index 73adcc1be5d..81d63a8e2c1 100644 --- a/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java +++ b/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java @@ -20,12 +20,15 @@ import static com.google.common.truth.Truth.assertThat; import static io.grpc.ConnectivityState.CONNECTING; import static io.grpc.ConnectivityState.READY; +import static io.grpc.ConnectivityState.TRANSIENT_FAILURE; +import static io.grpc.Status.UNAVAILABLE; import static io.grpc.xds.XdsSubchannelPickers.BUFFER_PICKER; import static org.mockito.AdditionalAnswers.delegatesTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; @@ -38,6 +41,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; import io.envoyproxy.envoy.api.v2.endpoint.ClusterStats; import io.grpc.ChannelLogger; import io.grpc.ClientStreamTracer; @@ -54,6 +58,8 @@ import io.grpc.LoadBalancerRegistry; import io.grpc.SynchronizationContext; import io.grpc.internal.FakeClock; +import io.grpc.internal.FakeClock.ScheduledTask; +import io.grpc.internal.FakeClock.TaskFilter; import io.grpc.xds.ClientLoadCounter.LoadRecordingStreamTracerFactory; import io.grpc.xds.ClientLoadCounter.MetricsRecordingListener; import io.grpc.xds.InterLocalityPicker.WeightedChildPicker; @@ -66,7 +72,9 @@ import io.grpc.xds.XdsComms.DropOverload; import io.grpc.xds.XdsComms.LbEndpoint; import io.grpc.xds.XdsComms.LocalityInfo; +import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; import java.net.InetSocketAddress; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -130,6 +138,20 @@ public void uncaughtException(Thread t, Throwable e) { private final Map childHelperWrappers = new HashMap<>(); private final FakeClock fakeClock = new FakeClock(); + private final TaskFilter deactivationTaskFilter = new TaskFilter() { + @Override + public boolean shouldAccept(Runnable runnable) { + return runnable.toString().contains("DeletionTask"); + } + }; + + private final TaskFilter failOverTaskFilter = new TaskFilter() { + @Override + public boolean shouldAccept(Runnable runnable) { + return runnable.toString().contains("FailOverTask"); + } + }; + private final LoadBalancerProvider lbProvider = new LoadBalancerProvider() { @Override @@ -236,27 +258,27 @@ public OrcaReportingHelperWrapper answer(InvocationOnMock invocation) { public void updateLocalityStore_updateStatsStoreLocalityTracking() { Map localityInfoMap = new HashMap<>(); localityInfoMap - .put(locality1, new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1)); + .put(locality1, new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0)); localityInfoMap - .put(locality2, new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2)); - localityStore.updateLocalityStore(localityInfoMap); + .put(locality2, new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0)); + localityStore.updateLocalityStore(ImmutableMap.copyOf(localityInfoMap)); verify(loadStatsStore).addLocality(locality1); verify(loadStatsStore).addLocality(locality2); localityInfoMap - .put(locality3, new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3)); - localityStore.updateLocalityStore(localityInfoMap); + .put(locality3, new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 0)); + localityStore.updateLocalityStore(ImmutableMap.copyOf(localityInfoMap)); verify(loadStatsStore).addLocality(locality3); localityInfoMap = ImmutableMap - .of(locality4, new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 4)); - localityStore.updateLocalityStore(localityInfoMap); + .of(locality4, new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 4, 0)); + localityStore.updateLocalityStore(ImmutableMap.copyOf(localityInfoMap)); verify(loadStatsStore).removeLocality(locality1); verify(loadStatsStore).removeLocality(locality2); verify(loadStatsStore).removeLocality(locality3); verify(loadStatsStore).addLocality(locality4); - localityStore.updateLocalityStore(Collections.EMPTY_MAP); + localityStore.updateLocalityStore(ImmutableMap.copyOf(Collections.EMPTY_MAP)); verify(loadStatsStore).removeLocality(locality4); } @@ -264,9 +286,9 @@ public void updateLocalityStore_updateStatsStoreLocalityTracking() { public void updateLocalityStore_pickResultInterceptedForLoadRecordingWhenSubchannelReady() { // Simulate receiving two localities. LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); localityStore.updateLocalityStore(ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2)); @@ -335,9 +357,9 @@ public void updateLocalityStore_pickResultInterceptedForLoadRecordingWhenSubchan public void childLbPerformOobBackendMetricsAggregation() { // Simulate receiving two localities. LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); localityStore.updateLocalityStore(ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2)); @@ -393,9 +415,9 @@ public void updateOobMetricsReportIntervalBeforeChildLbCreated() { // Simulate receiving two localities. LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); localityStore.updateLocalityStore(ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2)); @@ -412,12 +434,12 @@ public void updateOobMetricsReportIntervalBeforeChildLbCreated() { public void updateLoaclityStore_withEmptyDropList() { localityStore.updateDropPercentage(ImmutableList.of()); LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); LocalityInfo localityInfo3 = - new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3); - Map localityInfoMap = ImmutableMap.of( + new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 0); + ImmutableMap localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3); localityStore.updateLocalityStore(localityInfoMap); verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); @@ -491,9 +513,9 @@ public PickResult pickSubchannel(PickSubchannelArgs args) { // update with new addresses localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11), 1, 0); LocalityInfo localityInfo4 = - new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 4); + new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 4, 0); localityInfoMap = ImmutableMap.of( locality2, localityInfo2, locality4, localityInfo4, locality1, localityInfo1); localityStore.updateLocalityStore(localityInfoMap); @@ -522,12 +544,12 @@ public PickResult pickSubchannel(PickSubchannelArgs args) { @Test public void updateLoaclityStore_deactivateAndReactivate() { LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); LocalityInfo localityInfo3 = - new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3); - Map localityInfoMap = ImmutableMap.of( + new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 0); + ImmutableMap localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3); localityStore.updateLocalityStore(localityInfoMap); @@ -556,7 +578,7 @@ public PickResult pickSubchannel(PickSubchannelArgs args) { // update localities, removing sz1, sz2, keeping sz3, and adding sz4 LocalityInfo localityInfo4 = - new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 4); + new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 4, 0); localityInfoMap = ImmutableMap.of(locality3, localityInfo3, locality4, localityInfo4); localityStore.updateLocalityStore(localityInfoMap); @@ -622,7 +644,8 @@ public PickResult pickSubchannel(PickSubchannelArgs args) { pickerFactory.nextIndex = 0; assertThat(subchannelPickerCaptor.getValue().pickSubchannel(pickSubchannelArgs).getSubchannel()) .isEqualTo(subchannel1); - assertThat(fakeClock.getPendingTasks()).hasSize(2); // sz3, sz4 pending removal + // sz3, sz4 pending removal + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(2); // verify lb1, lb3, and lb4 never shutdown and never changed since created verify(lb1, never()).shutdown(); @@ -635,7 +658,7 @@ public PickResult pickSubchannel(PickSubchannelArgs args) { assertThat(loadBalancers.get("sz4")).isSameInstanceAs(lb4); localityStore.reset(); - assertThat(fakeClock.getPendingTasks()).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); verify(lb1).shutdown(); verify(newLb2).shutdown(); verify(lb3).shutdown(); @@ -648,12 +671,12 @@ public void updateLoaclityStore_withDrop() { new DropOverload("throttle", 365), new DropOverload("lb", 1234))); LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); LocalityInfo localityInfo3 = - new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3); - Map localityInfoMap = ImmutableMap.of( + new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 0); + ImmutableMap localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3); localityStore.updateLocalityStore(localityInfoMap); @@ -746,12 +769,12 @@ public void updateLoaclityStore_withAllDropBeforeLocalityUpdateConnectivityState new DropOverload("throttle", 365), new DropOverload("lb", 1000_000))); LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); LocalityInfo localityInfo3 = - new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3); - Map localityInfoMap = ImmutableMap.of( + new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 0); + ImmutableMap localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3); localityStore.updateLocalityStore(localityInfoMap); @@ -767,12 +790,12 @@ public void updateLoaclityStore_withAllDropBeforeLocalityUpdateConnectivityState @Test public void updateLocalityStore_OnlyUpdatingWeightsStillUpdatesPicker() { LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); LocalityInfo localityInfo3 = - new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3); - Map localityInfoMap = ImmutableMap.of( + new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 0); + ImmutableMap localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3); localityStore.updateLocalityStore(localityInfoMap); @@ -781,9 +804,9 @@ public void updateLocalityStore_OnlyUpdatingWeightsStillUpdatesPicker() { assertThat(pickerFactory.totalReadyLocalities).isEqualTo(0); // Update locality weights before any subchannel becomes READY. - localityInfo1 = new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 4); - localityInfo2 = new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 5); - localityInfo3 = new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 6); + localityInfo1 = new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 4, 0); + localityInfo2 = new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 5, 0); + localityInfo3 = new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 6, 0); localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3); localityStore.updateLocalityStore(localityInfoMap); @@ -816,10 +839,10 @@ public PickResult pickSubchannel(PickSubchannelArgs args) { @Test public void reset() { LocalityInfo localityInfo1 = - new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1); + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); LocalityInfo localityInfo2 = - new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2); - Map localityInfoMap = ImmutableMap.of( + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 0); + ImmutableMap localityInfoMap = ImmutableMap.of( locality1, localityInfo1, locality2, localityInfo2); localityStore.updateLocalityStore(localityInfoMap); @@ -842,6 +865,402 @@ public void reset() { verify(loadStatsStore, times(2)).removeLocality(locality2); } + /** + * Tests the scenario of the following sequence of events. + * (In the format of "event detail - expected state", with abbreviations C for CONNECTING, + * F for TRANSIENT_FAILURE, R for READ, and D for deactivated etc.) + * EDS update: P0 sz1; P1 sz2; P2 sz3; P3 sz4 - P0 C, P1 N/A, P2 N/A, P3 N/A + * 10 secs passes P0 still CONNECTING - P0 C, P1 C, P2 N/A, P3 N/A + * 5 secs passes P1 in TRANSIENT_FAILURE - P0 C, P1 F, P2 C, P3 N/A + * 4 secs passes P2 READY - P0 C, P1 F, P2 R, P3 N/A + * P0 gets READY - P0 R, P1 F&D, P2 R&D, P3 N/A + * P1 gets READY - P0 R, P1 R&D, P2 R&D, P3 N/A + * 10 min passes P0 in TRANSIENT_FAILURE - P0 F, P1 R, P2 R&D, P3 N/A + * 5 min passes - P0 F, P1 R, P2 N/A, P3 N/A + * P1 in TRANSIENT_FAILURE - P0 F, P1 F, P2 C, P3 N/A + * 10 secs passes - P0 F, P1 F, P2 C, P3 C + * P1, P3 gets READY - P0 F, P1 R, P2 C&D, P3 R&D + * EDS update, localities moved: P0 sz1, sz3; P1 sz4; P2 sz2 - P0 C, P1 R, P2 R&D + * 15 min passes - P0 C, P1 R, P2 N/A + * EDS update, locality removed: P0 sz1, sz3, - P0 C, P1 N/A, sz4 R&D + * sz3 gets READY - P0 R, P1 N/A, sz4 R&D + * EDS update, locality comes back and another removed: P0 sz1, P1 sz4 - P0 C, P1 R, sz3 R&D + * + *

Should also verify that when locality store is updated with new EDS data, state of all + * localities should be updated before the child balancer of each locality handles new addresses. + */ + @Test + public void multipriority() { + // EDS update: P0 sz1; P1 sz2; P2 sz3; P3 sz4 - P0 C, P1 N/A, P2 N/A, P3 N/A + LocalityInfo localityInfo1 = + new LocalityInfo(ImmutableList.of(lbEndpoint11, lbEndpoint12), 1, 0); + LocalityInfo localityInfo2 = + new LocalityInfo(ImmutableList.of(lbEndpoint21, lbEndpoint22), 2, 1); + LocalityInfo localityInfo3 = + new LocalityInfo(ImmutableList.of(lbEndpoint31, lbEndpoint32), 3, 2); + LocalityInfo localityInfo4 = + new LocalityInfo(ImmutableList.of(lbEndpoint41, lbEndpoint42), 3, 3); + final ImmutableMap localityInfoMap = ImmutableMap.of( + locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3, locality4, + localityInfo4); + syncContext.execute(new Runnable() { + @Override + public void run() { + localityStore.updateLocalityStore(localityInfoMap); + } + }); + assertThat(loadBalancers.keySet()).containsExactly("sz1"); + LoadBalancer lb1 = loadBalancers.get("sz1"); + InOrder inOrder = inOrder(lb1, helper); + ArgumentCaptor resolvedAddressesCaptor1 = ArgumentCaptor.forClass(null); + inOrder.verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); + inOrder.verify(lb1).handleResolvedAddresses(resolvedAddressesCaptor1.capture()); + assertThat(resolvedAddressesCaptor1.getValue().getAddresses()).containsExactly(eag11, eag12); + + // 10 sec passes P0 still CONNECTING - P0 C, P1 C, P2 N/A, P3 N/A + fakeClock.forwardTime(9, TimeUnit.SECONDS); + assertThat(loadBalancers.keySet()).containsExactly("sz1"); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).hasSize(1); + ScheduledTask failOverTask = + Iterables.getOnlyElement(fakeClock.getPendingTasks(failOverTaskFilter)); + fakeClock.forwardTime(1, TimeUnit.SECONDS); + assertThat(failOverTask.isCancelled()).isFalse(); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).doesNotContain(failOverTask); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).hasSize(1); + failOverTask = Iterables.getOnlyElement(fakeClock.getPendingTasks(failOverTaskFilter)); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + assertThat(loadBalancers.keySet()).containsExactly("sz1", "sz2"); + LoadBalancer lb2 = loadBalancers.get("sz2"); + inOrder = inOrder(lb1, lb2, helper); + inOrder.verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); + ArgumentCaptor resolvedAddressesCaptor2 = ArgumentCaptor.forClass(null); + inOrder.verify(lb2).handleResolvedAddresses(resolvedAddressesCaptor2.capture()); + assertThat(resolvedAddressesCaptor2.getValue().getAddresses()).containsExactly(eag21, eag22); + + // 5 secs passes P1 in TRANSIENT_FAILURE - P0 C, P1 F, P2 C, P3 N/A + fakeClock.forwardTime(5, TimeUnit.SECONDS); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).containsExactly(failOverTask); + final Helper helper2 = childHelpers.get("sz2"); + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper2.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(UNAVAILABLE)); + } + }); + assertThat(failOverTask.isCancelled()).isTrue(); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).doesNotContain(failOverTask); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).hasSize(1); + failOverTask = Iterables.getOnlyElement(fakeClock.getPendingTasks(failOverTaskFilter)); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + assertThat(loadBalancers.keySet()).containsExactly("sz1", "sz2", "sz3"); + LoadBalancer lb3 = loadBalancers.get("sz3"); + inOrder = inOrder(lb3, helper); + // The order of the following two updateBalancingState() does not matter. We want to verify + // lb3.handleResolvedAddresses() is after them. + inOrder.verify(helper).updateBalancingState(same(TRANSIENT_FAILURE), isA(ErrorPicker.class)); + inOrder.verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); + ArgumentCaptor resolvedAddressesCaptor3 = ArgumentCaptor.forClass(null); + inOrder.verify(lb3).handleResolvedAddresses(resolvedAddressesCaptor3.capture()); + assertThat(resolvedAddressesCaptor3.getValue().getAddresses()).containsExactly(eag31, eag32); + + // 5 secs passes P2 READY - P0 C, P1 F, P2 R, P3 N/A + fakeClock.forwardTime(4, TimeUnit.SECONDS); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).containsExactly(failOverTask); + final Helper helper3 = childHelpers.get("sz3"); + final Subchannel mockSubchannel3 = mock(Subchannel.class); + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper3.updateBalancingState( + READY, + new SubchannelPicker() { + @Override + public PickResult pickSubchannel(PickSubchannelArgs args) { + return PickResult.withSubchannel(mockSubchannel3); + } + }); + } + }); + assertThat(failOverTask.isCancelled()).isTrue(); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + ArgumentCaptor subchannelPickerCaptor = ArgumentCaptor.forClass(null); + inOrder.verify(helper).updateBalancingState(same(READY), subchannelPickerCaptor.capture()); + assertThat(subchannelPickerCaptor.getValue() + .pickSubchannel(mock(PickSubchannelArgs.class)) + .getSubchannel()) + .isSameInstanceAs(mockSubchannel3); + + // P0 gets READY - P0 R, P1 F&D, P2 R&D, P3 N/A + final Helper helper1 = childHelpers.get("sz1"); + final Subchannel mockSubchannel1 = mock(Subchannel.class); + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper1.updateBalancingState( + READY, + new SubchannelPicker() { + @Override + public PickResult pickSubchannel(PickSubchannelArgs args) { + return PickResult.withSubchannel(mockSubchannel1); + } + }); + } + }); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + Collection deactivationTasks = fakeClock.getPendingTasks(deactivationTaskFilter); + assertThat(deactivationTasks).hasSize(2); + inOrder.verify(helper).updateBalancingState(same(READY), subchannelPickerCaptor.capture()); + assertThat(subchannelPickerCaptor.getValue() + .pickSubchannel(mock(PickSubchannelArgs.class)) + .getSubchannel()) + .isSameInstanceAs(mockSubchannel1); + + // P1 gets READY - P0 R, P1 R&D, P2 R&D, P3 N/A + final Subchannel mockSubchannel2 = mock(Subchannel.class); + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper2.updateBalancingState( + READY, + new SubchannelPicker() { + @Override + public PickResult pickSubchannel(PickSubchannelArgs args) { + return PickResult.withSubchannel(mockSubchannel2); + } + }); + } + }); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(2); + inOrder.verify(helper, never()) + .updateBalancingState(any(ConnectivityState.class), any(SubchannelPicker.class)); + + // 10 min passes P0 in TRANSIENT_FAILURE - P0 F, P1 R, P2 R&D, P3 N/A + fakeClock.forwardTime(10, TimeUnit.MINUTES); + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper1.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(UNAVAILABLE)); + } + }); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(1); + ScheduledTask deactivationTask = + Iterables.getOnlyElement(fakeClock.getPendingTasks(deactivationTaskFilter)); + assertThat(deactivationTask).isSameInstanceAs(Iterables.get(deactivationTasks, 1)); + assertThat(Iterables.get(deactivationTasks, 0).isCancelled()).isTrue(); + inOrder.verify(helper, never()) + .updateBalancingState(CONNECTING, BUFFER_PICKER); + + + // 5 min passes - P0 F, P1 R, P2 N/A, P3 N/A + verify(lb3, never()).shutdown(); + fakeClock.forwardTime(5, TimeUnit.MINUTES); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + verify(lb3).shutdown(); + + // P1 in TRANSIENT_FAILURE - P0 F, P1 F, P2 C, P3 N/A + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper2.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(UNAVAILABLE)); + } + }); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).hasSize(1); + failOverTask = Iterables.getOnlyElement(fakeClock.getPendingTasks(failOverTaskFilter)); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + // The order of the following two updateBalancingState() does not matter. We only want to verify + // these are the latest tow updateBalancingState(). + inOrder.verify(helper).updateBalancingState(same(TRANSIENT_FAILURE), isA(ErrorPicker.class)); + inOrder.verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); + assertThat(loadBalancers.keySet()).containsExactly("sz1", "sz2", "sz3"); + assertThat(loadBalancers.get("sz3")).isNotSameInstanceAs(lb3); + lb3 = loadBalancers.get("sz3"); + assertThat(childHelpers.get("sz3")).isNotSameInstanceAs(helper3); + + // 10 secs passes - P0 F, P1 F, P2 C, P3 C + fakeClock.forwardTime(10, TimeUnit.SECONDS); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).hasSize(1); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).doesNotContain(failOverTask); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + assertThat(loadBalancers.keySet()).containsExactly("sz1", "sz2", "sz3", "sz4"); + LoadBalancer lb4 = loadBalancers.get("sz4"); + inOrder = inOrder(lb1, lb2, lb3, lb4, helper); + inOrder.verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); + ArgumentCaptor resolvedAddressesCaptor4 = ArgumentCaptor.forClass(null); + inOrder.verify(lb4).handleResolvedAddresses(resolvedAddressesCaptor4.capture()); + assertThat(resolvedAddressesCaptor4.getValue().getAddresses()).containsExactly(eag41, eag42); + + // P1, P3 gets READY - P0 F, P1 R, P2 C&D, P3 R&D + final Subchannel mockSubchannel22 = mock(Subchannel.class); + final Subchannel mockSubchannel4 = mock(Subchannel.class); + final Helper helper4 = childHelpers.get("sz4"); + helper.getSynchronizationContext().execute(new Runnable() { + @Override + public void run() { + helper2.updateBalancingState( + READY, + new SubchannelPicker() { + @Override + public PickResult pickSubchannel(PickSubchannelArgs args) { + return PickResult.withSubchannel(mockSubchannel22); + } + }); + helper4.updateBalancingState( + READY, + new SubchannelPicker() { + @Override + public PickResult pickSubchannel(PickSubchannelArgs args) { + return PickResult.withSubchannel(mockSubchannel4); + } + }); + } + }); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(2); + inOrder.verify(helper).updateBalancingState(same(READY), subchannelPickerCaptor.capture()); + assertThat(subchannelPickerCaptor.getValue() + .pickSubchannel(mock(PickSubchannelArgs.class)) + .getSubchannel()) + .isSameInstanceAs(mockSubchannel22); + + // EDS update, localities moved: P0 sz1, sz3; P1 sz4; P2 sz2 - P0 C, P1 R, P2 R&D + localityInfo1 = + new LocalityInfo(ImmutableList.of(lbEndpoint12), 1, 0); + localityInfo2 = + new LocalityInfo(ImmutableList.of(lbEndpoint22), 2, 2); + localityInfo3 = + new LocalityInfo(ImmutableList.of(lbEndpoint32), 3, 0); + localityInfo4 = + new LocalityInfo(ImmutableList.of(lbEndpoint42), 4, 1); + final ImmutableMap localityInfoMap2 = ImmutableMap.of( + locality1, localityInfo1, locality2, localityInfo2, locality3, localityInfo3, locality4, + localityInfo4); + syncContext.execute(new Runnable() { + @Override + public void run() { + localityStore.updateLocalityStore(localityInfoMap2); + } + }); + assertThat(loadBalancers.keySet()).containsExactly("sz1", "sz2", "sz3", "sz4"); + assertThat(loadBalancers.values()).containsExactly(lb1, lb2, lb3, lb4); + inOrder.verify(helper).updateBalancingState(same(READY), subchannelPickerCaptor.capture()); + assertThat(subchannelPickerCaptor.getValue() + .pickSubchannel(mock(PickSubchannelArgs.class)) + .getSubchannel()) + .isSameInstanceAs(mockSubchannel4); + // The order of the following four handleResolvedAddresses() does not matter. We want to verify + // they are after helper.updateBalancingState() + inOrder.verify(lb1).handleResolvedAddresses(resolvedAddressesCaptor1.capture()); + assertThat(resolvedAddressesCaptor1.getValue().getAddresses()).containsExactly(eag12); + inOrder.verify(lb2).handleResolvedAddresses(resolvedAddressesCaptor2.capture()); + assertThat(resolvedAddressesCaptor2.getValue().getAddresses()).containsExactly(eag22); + inOrder.verify(lb3).handleResolvedAddresses(resolvedAddressesCaptor3.capture()); + assertThat(resolvedAddressesCaptor3.getValue().getAddresses()).containsExactly(eag32); + inOrder.verify(lb4).handleResolvedAddresses(resolvedAddressesCaptor4.capture()); + assertThat(resolvedAddressesCaptor4.getValue().getAddresses()).containsExactly(eag42); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(1); + + // 15 min passes - P0 C, P1 R, P2 N/A + verify(lb2, never()).shutdown(); + fakeClock.forwardTime(15, TimeUnit.MINUTES); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + inOrder.verify(lb2).shutdown(); + inOrder.verifyNoMoreInteractions(); + + // EDS update, locality removed: P0 sz1, sz3, - P0 C, P1 N/A, sz4 R&D + localityInfo1 = + new LocalityInfo(ImmutableList.of(lbEndpoint11), 1, 0); + localityInfo3 = + new LocalityInfo(ImmutableList.of(lbEndpoint31), 3, 0); + final ImmutableMap localityInfoMap3 = ImmutableMap.of( + locality1, localityInfo1,locality3, localityInfo3); + syncContext.execute(new Runnable() { + @Override + public void run() { + localityStore.updateLocalityStore(localityInfoMap3); + } + }); + inOrder.verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); + // The order of the following two handleResolvedAddresses() does not matter. We want to verify + // they are after helper.updateBalancingState() + inOrder.verify(lb1).handleResolvedAddresses(resolvedAddressesCaptor1.capture()); + assertThat(resolvedAddressesCaptor1.getValue().getAddresses()).containsExactly(eag11); + inOrder.verify(lb3).handleResolvedAddresses(resolvedAddressesCaptor3.capture()); + assertThat(resolvedAddressesCaptor3.getValue().getAddresses()).containsExactly(eag31); + inOrder.verifyNoMoreInteractions(); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(1); + + // sz3 gets READY - P0 R, P1 N/A, sz4 R&D + final Helper newHelper3 = childHelpers.get("sz3"); + final Subchannel newMockSubchannel3 = mock(Subchannel.class); + syncContext.execute(new Runnable() { + @Override + public void run() { + newHelper3.updateBalancingState( + READY, + new SubchannelPicker() { + @Override + public PickResult pickSubchannel(PickSubchannelArgs args) { + return PickResult.withSubchannel(newMockSubchannel3); + } + } + ); + } + }); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(1); + inOrder.verify(helper).updateBalancingState(same(READY), subchannelPickerCaptor.capture()); + assertThat(subchannelPickerCaptor.getValue() + .pickSubchannel(mock(PickSubchannelArgs.class)) + .getSubchannel()) + .isSameInstanceAs(newMockSubchannel3); + inOrder.verifyNoMoreInteractions(); + + // EDS update, locality comes back and another removed: P0 sz1, P1 sz4 - P0 C, P1 R, sz3 R&D + localityInfo1 = + new LocalityInfo(ImmutableList.of(lbEndpoint11), 1, 0); + localityInfo4 = + new LocalityInfo(ImmutableList.of(lbEndpoint41), 4, 1); + final ImmutableMap localityInfoMap4 = ImmutableMap.of( + locality1, localityInfo1,locality4, localityInfo4); + syncContext.execute(new Runnable() { + @Override + public void run() { + localityStore.updateLocalityStore(localityInfoMap4); + } + }); + inOrder.verify(helper, atLeastOnce()).updateBalancingState( + same(READY), subchannelPickerCaptor.capture()); + assertThat(subchannelPickerCaptor.getValue() + .pickSubchannel(mock(PickSubchannelArgs.class)) + .getSubchannel()) + .isSameInstanceAs(mockSubchannel4); + // The order of the following two handleResolvedAddresses() does not matter. We want to verify + // they are after helper.updateBalancingState() + inOrder.verify(lb1).handleResolvedAddresses(resolvedAddressesCaptor1.capture()); + assertThat(resolvedAddressesCaptor1.getValue().getAddresses()).containsExactly(eag11); + inOrder.verify(lb4).handleResolvedAddresses(resolvedAddressesCaptor4.capture()); + assertThat(resolvedAddressesCaptor4.getValue().getAddresses()).containsExactly(eag41); + inOrder.verifyNoMoreInteractions(); + assertThat(fakeClock.getPendingTasks(failOverTaskFilter)).isEmpty(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).hasSize(1); + + verify(lb1, never()).shutdown(); + verify(lb3, never()).shutdown(); + verify(lb4, never()).shutdown(); + localityStore.reset(); + assertThat(fakeClock.getPendingTasks(deactivationTaskFilter)).isEmpty(); + verify(lb1).shutdown(); + verify(lb3).shutdown(); + verify(lb4).shutdown(); + } + private static final class FakeLoadStatsStore implements LoadStatsStore { Map localityCounters = new HashMap<>(); diff --git a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java index c3eb3bf5221..8e35a75f73a 100644 --- a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; import com.google.protobuf.UInt32Value; import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; @@ -64,7 +65,6 @@ import io.grpc.xds.XdsComms.AdsStreamCallback; import io.grpc.xds.XdsComms.DropOverload; import io.grpc.xds.XdsComms.LocalityInfo; -import java.util.Map; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Rule; @@ -107,7 +107,7 @@ public boolean shouldAccept(Runnable command) { @Mock private BackoffPolicy backoffPolicy2; @Captor - private ArgumentCaptor> localityEndpointsMappingCaptor; + private ArgumentCaptor> localityEndpointsMappingCaptor; private final FakeClock fakeClock = new FakeClock(); private final SynchronizationContext syncContext = new SynchronizationContext( @@ -293,12 +293,14 @@ public void standardMode_sendEdsRequest_getEdsResponse_withNoDrop() { ImmutableList.of( new XdsComms.LbEndpoint(endpoint11), new XdsComms.LbEndpoint(endpoint12)), - 1); + 1, + 0); LocalityInfo localityInfo2 = new LocalityInfo( ImmutableList.of( new XdsComms.LbEndpoint(endpoint21), new XdsComms.LbEndpoint(endpoint22)), - 2); + 2, + 0); XdsLocality locality2 = XdsLocality.fromLocalityProto(localityProto2); InOrder inOrder = inOrder(localityStore); @@ -405,9 +407,9 @@ public void standardMode_sendEdsRequest_getEdsResponse_withDrops() { XdsLocality locality1 = XdsLocality.fromLocalityProto(localityProto1); LocalityInfo localityInfo1 = new LocalityInfo( - ImmutableList.of(new XdsComms.LbEndpoint(endpoint11)), 1); + ImmutableList.of(new XdsComms.LbEndpoint(endpoint11)), 1, 0); LocalityInfo localityInfo2 = new LocalityInfo( - ImmutableList.of(new XdsComms.LbEndpoint(endpoint21)), 2); + ImmutableList.of(new XdsComms.LbEndpoint(endpoint21)), 2, 0); XdsLocality locality2 = XdsLocality.fromLocalityProto(localityProto2); assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( locality2, localityInfo2, locality1, localityInfo1).inOrder(); diff --git a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java index 5bc701bb4e6..d6c9a8a5458 100644 --- a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java @@ -72,6 +72,7 @@ import io.grpc.inprocess.InProcessServerBuilder; import io.grpc.internal.BackoffPolicy; import io.grpc.internal.FakeClock; +import io.grpc.internal.FakeClock.TaskFilter; import io.grpc.internal.JsonParser; import io.grpc.internal.testing.StreamRecorder; import io.grpc.stub.StreamObserver; @@ -214,6 +215,13 @@ public void uncaughtException(Thread t, Throwable e) { } }); + private final TaskFilter fallbackTaskFilter = new TaskFilter() { + @Override + public boolean shouldAccept(Runnable runnable) { + return runnable.toString().contains("FallbackTask"); + } + }; + private ManagedChannel oobChannel1; private ManagedChannel oobChannel2; private ManagedChannel oobChannel3; @@ -579,7 +587,7 @@ public void fallback_AdsNotWorkingYetTimerExpired() throws Exception { assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1); - assertThat(fakeClock.getPendingTasks()).isEmpty(); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); assertNull(childHelper); assertNotNull(fallbackHelper1); ArgumentCaptor captor = ArgumentCaptor.forClass(ResolvedAddresses.class); @@ -617,7 +625,7 @@ public void allDropCancelsFallbackTimer() throws Exception { .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") .build(); serverResponseWriter.onNext(edsResponse); - assertThat(fakeClock.getPendingTasks()).isEmpty(); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); assertNotNull(childHelper); assertNull(fallbackHelper1); verify(fallbackBalancer1, never()).handleResolvedAddresses(any(ResolvedAddresses.class)); @@ -634,7 +642,7 @@ public void allDropExitFallbackMode() throws Exception { // let the fallback timer expire assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1); - assertThat(fakeClock.getPendingTasks()).isEmpty(); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); assertNull(childHelper); assertNotNull(fallbackHelper1); @@ -677,12 +685,12 @@ public void fallback_ErrorWithoutReceivingEdsResponse() throws Exception { assertNull(childHelper); assertNull(fallbackHelper1); - assertThat(fakeClock.getPendingTasks()).hasSize(1); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).hasSize(1); serverResponseWriter.onError(new Exception("fake error")); // goes to fallback-at-startup mode immediately - assertThat(fakeClock.getPendingTasks()).isEmpty(); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); assertNull(childHelper); assertNotNull(fallbackHelper1); // verify fallback balancer is working @@ -709,7 +717,7 @@ public void fallback_EdsResponseReceivedThenErrorBeforeBackendReady() throws Exc verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); serverResponseWriter.onError(new Exception("fake error")); - assertThat(fakeClock.getPendingTasks()).hasSize(1); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).hasSize(1); // verify fallback balancer is not started assertNull(fallbackHelper1); verify(fallbackBalancer1, never()).handleResolvedAddresses(any(ResolvedAddresses.class)); @@ -753,13 +761,13 @@ public void fallback_AdsErrorWithActiveSubchannel() throws Exception { .build()); serverResponseWriter.onNext(edsResponse); assertNotNull(childHelper); - assertThat(fakeClock.getPendingTasks()).hasSize(1); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).hasSize(1); assertNull(fallbackHelper1); verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); childHelper.updateBalancingState(READY, mock(SubchannelPicker.class)); verify(helper).updateBalancingState(same(READY), isA(InterLocalityPicker.class)); - assertThat(fakeClock.getPendingTasks()).isEmpty(); + assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); serverResponseWriter.onError(new Exception("fake error")); assertNull(fallbackHelper1); From f9ba620309a0dd46e5c0fc2c776677f9366be65d Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Tue, 24 Sep 2019 09:52:03 -0700 Subject: [PATCH 029/131] xds: shade gogoproto --- xds/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/xds/build.gradle b/xds/build.gradle index ce07abf6b89..8d5423aec44 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -71,6 +71,7 @@ shadowJar { include(dependency('io.envoyproxy.protoc-gen-validate:')) } relocate 'com.github.udpa', 'io.grpc.xds.shaded.com.github.udpa' + relocate 'com.google.protobuf.GoGoProtos', 'io.grpc.xds.shaded.gogoproto.GoGoProtos' relocate 'io.envoyproxy', 'io.grpc.xds.shaded.io.envoyproxy' exclude "**/*.proto" } From e281c75b2a0fab2b44f177defb39a017decbb101 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Tue, 24 Sep 2019 13:24:59 -0700 Subject: [PATCH 030/131] cronet: update README for using published grpc-cronet with play service Cronet implementation (#6178) * cronet: update README for using published grpc-cronet with play service Cronet implementation. * doc: Added cronet/README.md version update to RELEASING.md. --- RELEASING.md | 1 + cronet/README.md | 30 +++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index f610ab3d6bd..c18b117ec4b 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -119,6 +119,7 @@ Tagging the Release # Bump documented versions. Don't forget protobuf version $ ${EDITOR:-nano -w} README.md $ ${EDITOR:-nano -w} documentation/android-channel-builder.md + $ ${EDITOR:-nano -w} cronet/README.md $ git commit -a -m "Update README etc to reference $MAJOR.$MINOR.$PATCH" ``` 3. Change root build files to remove "-SNAPSHOT" for the next release version diff --git a/cronet/README.md b/cronet/README.md index f1c71cc8f43..613f3fb265c 100644 --- a/cronet/README.md +++ b/cronet/README.md @@ -1,9 +1,8 @@ gRPC Cronet Transport ======================== -**EXPERIMENTAL:** *gRPC's Cronet transport is an experimental API, and is not -yet integrated with our build system. Using Cronet with gRPC requires manually -integrating the gRPC code in this directory into your Android application.* +**EXPERIMENTAL:** *gRPC's Cronet transport is an experimental API, its stability +depends on upstream Cronet's implementation, which involves some experimental features.* This code enables using the [Chromium networking stack (Cronet)](https://chromium.googlesource.com/chromium/src/+/master/components/cronet) @@ -17,13 +16,26 @@ Some advantages of using Cronet with gRPC: * Robust to Android network connectivity changes * Support for [QUIC](https://www.chromium.org/quic) -Cronet jars are available on Google's Maven repository. See the example app at -https://github.com/GoogleChrome/cronet-sample/blob/master/README.md. To use -Cronet with gRPC, you will need to copy the gRPC source files contained in this -directory into your application's code, as we do not currently provide a -`grpc-cronet` dependency. +Since gRPC's 1.24 release, the `grpc-cronet` package provides access to the +`CronetChannelBuilder` class. Cronet jars are available on Google's Maven repository. +See the example app at https://github.com/GoogleChrome/cronet-sample/blob/master/README.md. -To use Cronet, you must have the `ACCESS_NETWORK_STATE` permission set in +## Example usage: + +In your app module's `build.gradle` file, include a dependency on both `grpc-cronet` and the +Google Play Services Client Library for Cronet + +``` +implementation 'io.grpc:grpc-cronet:1.24.0' +implementation 'com.google.android.gms:play-services-cronet:16.0.0' +``` + +In cases where Cronet cannot be loaded from Google Play services, there is a less performant +implementation of Cronet's API that can be used. Depend on `org.chromium.net:cronet-fallback` +to use this fall-back implementation. + + +You will also need permission to access the device's network state in your `AndroidManifest.xml`: ``` From 694de41107b9dbb4c512c88a49838923f2eff28e Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Wed, 25 Sep 2019 12:48:03 -0700 Subject: [PATCH 031/131] xds: add server name in EDS request resource_names field --- xds/src/main/java/io/grpc/xds/XdsComms.java | 8 +++----- xds/src/test/java/io/grpc/xds/XdsCommsTest.java | 1 + 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsComms.java b/xds/src/main/java/io/grpc/xds/XdsComms.java index ca5f1b44544..57cf24e4cc4 100644 --- a/xds/src/main/java/io/grpc/xds/XdsComms.java +++ b/xds/src/main/java/io/grpc/xds/XdsComms.java @@ -344,14 +344,12 @@ public void run() { DiscoveryRequest.newBuilder() .setNode(Node.newBuilder() .setMetadata(Struct.newBuilder() - .putFields( - TRAFFICDIRECTOR_GRPC_HOSTNAME, - Value.newBuilder().setStringValue(helper.getAuthority()) - .build()) .putFields( "endpoints_required", Value.newBuilder().setBoolValue(true).build()))) - .setTypeUrl(EDS_TYPE_URL).build(); + .setTypeUrl(EDS_TYPE_URL) + // In the future, the right resource name can be obtained from CDS response. + .addResourceNames(helper.getAuthority()).build(); helper.getChannelLogger().log(ChannelLogLevel.DEBUG, "Sending EDS request {0}", edsRequest); xdsRequestWriter.onNext(edsRequest); } diff --git a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java index 8e35a75f73a..c69e689ebc6 100644 --- a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java @@ -223,6 +223,7 @@ public void standardMode_sendEdsRequest_getEdsResponse_withNoDrop() { assertThat( request.getNode().getMetadata().getFieldsOrThrow("endpoints_required").getBoolValue()) .isTrue(); + assertThat(request.getResourceNamesList()).hasSize(1); Locality localityProto1 = Locality.newBuilder() .setRegion("region1").setZone("zone1").setSubZone("subzone1").build(); From 1ab651073d803e2a6dc77465434eadbca5336c59 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Wed, 25 Sep 2019 13:23:52 -0700 Subject: [PATCH 032/131] alts: add close to TsiHandshaker to avoid resource leak for some impls (#6186) * alts: add close to TsiHandshaker to avoid resource leak for some implementations * fix linter error --- .../main/java/io/grpc/alts/internal/AltsTsiHandshaker.java | 5 +++++ .../main/java/io/grpc/alts/internal/NettyTsiHandshaker.java | 4 ++++ .../main/java/io/grpc/alts/internal/TsiHandshakeHandler.java | 5 +++++ alts/src/main/java/io/grpc/alts/internal/TsiHandshaker.java | 5 +++++ .../io/grpc/alts/internal/AltsProtocolNegotiatorTest.java | 5 +++++ .../test/java/io/grpc/alts/internal/FakeTsiHandshaker.java | 5 +++++ 6 files changed, 29 insertions(+) diff --git a/alts/src/main/java/io/grpc/alts/internal/AltsTsiHandshaker.java b/alts/src/main/java/io/grpc/alts/internal/AltsTsiHandshaker.java index c8978cfa417..3cd639ad5ff 100644 --- a/alts/src/main/java/io/grpc/alts/internal/AltsTsiHandshaker.java +++ b/alts/src/main/java/io/grpc/alts/internal/AltsTsiHandshaker.java @@ -192,4 +192,9 @@ public TsiFrameProtector createFrameProtector(int maxFrameSize, ByteBufAllocator public TsiFrameProtector createFrameProtector(ByteBufAllocator alloc) { return createFrameProtector(AltsTsiFrameProtector.getMaxAllowedFrameBytes(), alloc); } + + @Override + public void close() { + handshaker.close(); + } } diff --git a/alts/src/main/java/io/grpc/alts/internal/NettyTsiHandshaker.java b/alts/src/main/java/io/grpc/alts/internal/NettyTsiHandshaker.java index 8d4bbd1a21e..5087123ab06 100644 --- a/alts/src/main/java/io/grpc/alts/internal/NettyTsiHandshaker.java +++ b/alts/src/main/java/io/grpc/alts/internal/NettyTsiHandshaker.java @@ -149,4 +149,8 @@ TsiFrameProtector createFrameProtector(ByteBufAllocator alloc) { unwrapper = null; return internalHandshaker.createFrameProtector(alloc); } + + void close() { + internalHandshaker.close(); + } } diff --git a/alts/src/main/java/io/grpc/alts/internal/TsiHandshakeHandler.java b/alts/src/main/java/io/grpc/alts/internal/TsiHandshakeHandler.java index 2664ba8f4f7..a4123a7a53e 100644 --- a/alts/src/main/java/io/grpc/alts/internal/TsiHandshakeHandler.java +++ b/alts/src/main/java/io/grpc/alts/internal/TsiHandshakeHandler.java @@ -185,4 +185,9 @@ private void sendHandshake(ChannelHandlerContext ctx) throws GeneralSecurityExce } } } + + @Override + protected void handlerRemoved0(ChannelHandlerContext ctx) throws Exception { + handshaker.close(); + } } \ No newline at end of file diff --git a/alts/src/main/java/io/grpc/alts/internal/TsiHandshaker.java b/alts/src/main/java/io/grpc/alts/internal/TsiHandshaker.java index 967582aa811..35b945770d2 100644 --- a/alts/src/main/java/io/grpc/alts/internal/TsiHandshaker.java +++ b/alts/src/main/java/io/grpc/alts/internal/TsiHandshaker.java @@ -106,4 +106,9 @@ public interface TsiHandshaker { * @return a new TsiFrameProtector. */ TsiFrameProtector createFrameProtector(ByteBufAllocator alloc); + + /** + * Closes resources. + */ + void close(); } diff --git a/alts/src/test/java/io/grpc/alts/internal/AltsProtocolNegotiatorTest.java b/alts/src/test/java/io/grpc/alts/internal/AltsProtocolNegotiatorTest.java index 67c3859b6af..395090dbd83 100644 --- a/alts/src/test/java/io/grpc/alts/internal/AltsProtocolNegotiatorTest.java +++ b/alts/src/test/java/io/grpc/alts/internal/AltsProtocolNegotiatorTest.java @@ -479,6 +479,11 @@ public TsiFrameProtector createFrameProtector(int maxFrameSize, ByteBufAllocator protectors.add(protector); return protector; } + + @Override + public void close() { + delegate.close(); + } } private static class InterceptingProtector implements TsiFrameProtector { diff --git a/alts/src/test/java/io/grpc/alts/internal/FakeTsiHandshaker.java b/alts/src/test/java/io/grpc/alts/internal/FakeTsiHandshaker.java index d742607618a..a04bbfd07e8 100644 --- a/alts/src/test/java/io/grpc/alts/internal/FakeTsiHandshaker.java +++ b/alts/src/test/java/io/grpc/alts/internal/FakeTsiHandshaker.java @@ -226,4 +226,9 @@ public TsiFrameProtector createFrameProtector(int maxFrameSize, ByteBufAllocator public TsiFrameProtector createFrameProtector(ByteBufAllocator alloc) { return createFrameProtector(AltsTsiFrameProtector.getMaxAllowedFrameBytes(), alloc); } + + @Override + public void close() { + // No-op + } } From 5912d620195b3e147aa44a6ffe3a6d74690c522a Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Wed, 25 Sep 2019 13:44:01 -0700 Subject: [PATCH 033/131] github: update issue templates (#6191) --- .github/ISSUE_TEMPLATE | 8 -------- .github/ISSUE_TEMPLATE/ask_question.md | 12 ++++++++++++ .github/ISSUE_TEMPLATE/bug_report.md | 19 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_report.md | 17 +++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE create mode 100644 .github/ISSUE_TEMPLATE/ask_question.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_report.md diff --git a/.github/ISSUE_TEMPLATE b/.github/ISSUE_TEMPLATE deleted file mode 100644 index 431fcb1f09c..00000000000 --- a/.github/ISSUE_TEMPLATE +++ /dev/null @@ -1,8 +0,0 @@ -Please answer these questions before submitting your issue. - -### What version of gRPC are you using? - - -### What did you expect to see? - - diff --git a/.github/ISSUE_TEMPLATE/ask_question.md b/.github/ISSUE_TEMPLATE/ask_question.md new file mode 100644 index 00000000000..573a0d55e69 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ask_question.md @@ -0,0 +1,12 @@ +--- +name: Ask a question +about: Asking a question related gRPC-Java +labels: question +--- + +For questions not directly related to gRPC-Java, please use [stackoverflow](https://stackoverflow.com/questions/tagged/grpc-java). +Also, if question is not gRPC-Java implementation specific, consider using [grpc.io](https://groups.google.com/forum/#!forum/grpc-io). + +Make sure you include information that can help us understand your question. + +[[Your question here]] diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..f72c4266a48 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,19 @@ +--- +name: Report a bug +about: Create a bug report to help us improve +labels: bug +--- + +Please answer these questions before submitting a bug report. + +### What version of gRPC are you using? + +### What operating system (Linux, Windows,...) and version? + +### What did you expect to see? + +### What did you see instead? + +### Steps to reproduce the bug + +Make sure you include information that can help us debug (full error message, exception listing, stack trace, logs). diff --git a/.github/ISSUE_TEMPLATE/feature_report.md b/.github/ISSUE_TEMPLATE/feature_report.md new file mode 100644 index 00000000000..c5f8c8b2ed0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_report.md @@ -0,0 +1,17 @@ +--- +name: Request a feature +about: Suggest an enhancement for gRPC +labels: enhancement +--- + +### Is your feature request related to a problem? Please describe. +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +### Describe the solution you'd like +A clear and concise description of what you want to happen. + +### Describe alternatives you've considered +A clear and concise description of any alternative solutions or features you've considered. + +### Additional context +Add any other context about the feature request here. From bd48891dab45e6c47f29a1fd85ff5420bd44c404 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 25 Sep 2019 07:10:26 -0700 Subject: [PATCH 034/131] netty: Check for TE header after checking Content-Type Checking too early leads to false-positives, like if a non-gRPC client contacts the server or a grpc-web client. --- .../java/io/grpc/netty/NettyServerHandler.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/NettyServerHandler.java b/netty/src/main/java/io/grpc/netty/NettyServerHandler.java index b5f95c8000a..13d5fb86b28 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerHandler.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerHandler.java @@ -370,13 +370,6 @@ public TransportTracer.FlowControlWindows read() { private void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers headers) throws Http2Exception { - if (!teWarningLogged && !TE_TRAILERS.contentEquals(headers.get(TE_HEADER))) { - logger.warning(String.format("Expected header TE: %s, but %s is received. This means " - + "some intermediate proxy may not support trailers", - TE_TRAILERS, headers.get(TE_HEADER))); - teWarningLogged = true; - } - try { // Remove the leading slash of the path and get the fully qualified method name @@ -416,6 +409,13 @@ private void onHeadersRead(ChannelHandlerContext ctx, int streamId, Http2Headers return; } + if (!teWarningLogged && !TE_TRAILERS.contentEquals(headers.get(TE_HEADER))) { + logger.warning(String.format("Expected header TE: %s, but %s is received. This means " + + "some intermediate proxy may not support trailers", + TE_TRAILERS, headers.get(TE_HEADER))); + teWarningLogged = true; + } + // The Http2Stream object was put by AbstractHttp2ConnectionHandler before calling this // method. Http2Stream http2Stream = requireHttp2Stream(streamId); From ab2aff48dcaa2944edc39b3881c59863a58dbab9 Mon Sep 17 00:00:00 2001 From: Carl Mastrangelo Date: Wed, 25 Sep 2019 14:57:17 -0700 Subject: [PATCH 035/131] netty,okhttp,cronet: add option to use get/put when methods are safe/idempotent This change adds two booleans to the ChannelBuilders to allow transports to use get and put. These are currently defaulted to on, but unset on the method descriptors. This change is 1/2 that will allow the safe / idempotent bits to be set on generated proto code. Part 2/2 will actually enable it. The use case for this is for interceptors that implement caching logic. They need to be able to access the safe/idempotent bits on the MD in order to decide to how to handle the request, even if gRPC doesn't use GET / PUT HTTP methods. --- .../io/grpc/cronet/CronetChannelBuilder.java | 25 +++++++++++++++-- .../io/grpc/cronet/CronetClientStream.java | 8 ++++-- .../io/grpc/cronet/CronetClientTransport.java | 11 ++++++-- .../grpc/cronet/CronetClientStreamTest.java | 28 ++++++++++++++----- .../cronet/CronetClientTransportTest.java | 4 ++- .../integration/AbstractInteropTest.java | 3 ++ .../io/grpc/netty/NettyChannelBuilder.java | 15 ++++++++-- .../java/io/grpc/netty/NettyClientStream.java | 9 ++---- .../io/grpc/netty/NettyClientTransport.java | 8 ++++-- .../io/grpc/netty/NettyClientStreamTest.java | 12 +++++--- .../grpc/netty/NettyClientTransportTest.java | 6 ++-- .../io/grpc/okhttp/OkHttpChannelBuilder.java | 17 +++++++++-- .../io/grpc/okhttp/OkHttpClientStream.java | 5 ++-- .../io/grpc/okhttp/OkHttpClientTransport.java | 9 ++++-- .../grpc/okhttp/OkHttpClientStreamTest.java | 9 +++--- .../okhttp/OkHttpClientTransportTest.java | 21 +++++++++----- 16 files changed, 138 insertions(+), 52 deletions(-) diff --git a/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java b/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java index e40691e453b..2fa71220054 100644 --- a/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java +++ b/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java @@ -86,6 +86,17 @@ public static CronetChannelBuilder forAddress(String name, int port) { private int maxMessageSize = DEFAULT_MAX_MESSAGE_SIZE; + /** + * If true, indicates that the transport may use the GET method for RPCs, and may include the + * request body in the query params. + */ + private final boolean useGetForSafeMethods = false; + + /** + * If true, indicates that the transport may use the PUT method for RPCs. + */ + private final boolean usePutForIdempotentMethods = false; + private boolean trafficStatsTagSet; private int trafficStatsTag; private boolean trafficStatsUidSet; @@ -194,7 +205,9 @@ protected final ClientTransportFactory buildTransportFactory() { scheduledExecutorService, maxMessageSize, alwaysUsePut, - transportTracerFactory.create()); + transportTracerFactory.create(), + useGetForSafeMethods, + usePutForIdempotentMethods); } @VisibleForTesting @@ -206,6 +219,8 @@ static class CronetTransportFactory implements ClientTransportFactory { private final StreamBuilderFactory streamFactory; private final TransportTracer transportTracer; private final boolean usingSharedScheduler; + private final boolean useGetForSafeMethods; + private final boolean usePutForIdempotentMethods; private CronetTransportFactory( StreamBuilderFactory streamFactory, @@ -213,7 +228,9 @@ private CronetTransportFactory( @Nullable ScheduledExecutorService timeoutService, int maxMessageSize, boolean alwaysUsePut, - TransportTracer transportTracer) { + TransportTracer transportTracer, + boolean useGetForSafeMethods, + boolean usePutForIdempotentMethods) { usingSharedScheduler = timeoutService == null; this.timeoutService = usingSharedScheduler ? SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE) : timeoutService; @@ -222,6 +239,8 @@ private CronetTransportFactory( this.streamFactory = streamFactory; this.executor = Preconditions.checkNotNull(executor, "executor"); this.transportTracer = Preconditions.checkNotNull(transportTracer, "transportTracer"); + this.useGetForSafeMethods = useGetForSafeMethods; + this.usePutForIdempotentMethods = usePutForIdempotentMethods; } @Override @@ -230,7 +249,7 @@ public ConnectionClientTransport newClientTransport( InetSocketAddress inetSocketAddr = (InetSocketAddress) addr; return new CronetClientTransport(streamFactory, inetSocketAddr, options.getAuthority(), options.getUserAgent(), options.getEagAttributes(), executor, maxMessageSize, - alwaysUsePut, transportTracer); + alwaysUsePut, transportTracer, useGetForSafeMethods, usePutForIdempotentMethods); } @Override diff --git a/cronet/src/main/java/io/grpc/cronet/CronetClientStream.java b/cronet/src/main/java/io/grpc/cronet/CronetClientStream.java index 4fde69d30f7..721432f8342 100644 --- a/cronet/src/main/java/io/grpc/cronet/CronetClientStream.java +++ b/cronet/src/main/java/io/grpc/cronet/CronetClientStream.java @@ -107,10 +107,12 @@ class CronetClientStream extends AbstractClientStream { MethodDescriptor method, StatsTraceContext statsTraceCtx, CallOptions callOptions, - TransportTracer transportTracer) { + TransportTracer transportTracer, + boolean useGetForSafeMethods, + boolean usePutForIdempotentMethods) { super( new CronetWritableBufferAllocator(), statsTraceCtx, transportTracer, headers, callOptions, - method.isSafe()); + useGetForSafeMethods && method.isSafe()); this.url = Preconditions.checkNotNull(url, "url"); this.userAgent = Preconditions.checkNotNull(userAgent, "userAgent"); this.statsTraceCtx = Preconditions.checkNotNull(statsTraceCtx, "statsTraceCtx"); @@ -118,7 +120,7 @@ class CronetClientStream extends AbstractClientStream { this.headers = Preconditions.checkNotNull(headers, "headers"); this.transport = Preconditions.checkNotNull(transport, "transport"); this.startCallback = Preconditions.checkNotNull(startCallback, "startCallback"); - this.idempotent = method.isIdempotent() || alwaysUsePut; + this.idempotent = (usePutForIdempotentMethods && method.isIdempotent()) || alwaysUsePut; // Only delay flushing header for unary rpcs. this.delayRequestHeader = (method.getType() == MethodDescriptor.MethodType.UNARY); this.annotation = callOptions.getOption(CRONET_ANNOTATION_KEY); diff --git a/cronet/src/main/java/io/grpc/cronet/CronetClientTransport.java b/cronet/src/main/java/io/grpc/cronet/CronetClientTransport.java index 2c7b2326c9e..1e946ead1fc 100644 --- a/cronet/src/main/java/io/grpc/cronet/CronetClientTransport.java +++ b/cronet/src/main/java/io/grpc/cronet/CronetClientTransport.java @@ -60,6 +60,8 @@ class CronetClientTransport implements ConnectionClientTransport { private final boolean alwaysUsePut; private final TransportTracer transportTracer; private final Attributes attrs; + private final boolean useGetForSafeMethods; + private final boolean usePutForIdempotentMethods; // Indicates the transport is in go-away state: no new streams will be processed, // but existing streams may continue. @GuardedBy("lock") @@ -86,7 +88,9 @@ class CronetClientTransport implements ConnectionClientTransport { Executor executor, int maxMessageSize, boolean alwaysUsePut, - TransportTracer transportTracer) { + TransportTracer transportTracer, + boolean useGetForSafeMethods, + boolean usePutForIdempotentMethods) { this.address = Preconditions.checkNotNull(address, "address"); this.logId = InternalLogId.allocate(getClass(), address.toString()); this.authority = authority; @@ -100,6 +104,8 @@ class CronetClientTransport implements ConnectionClientTransport { .set(GrpcAttributes.ATTR_SECURITY_LEVEL, SecurityLevel.PRIVACY_AND_INTEGRITY) .set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, eagAttrs) .build(); + this.useGetForSafeMethods = useGetForSafeMethods; + this.usePutForIdempotentMethods = usePutForIdempotentMethods; } @Override @@ -123,7 +129,8 @@ public CronetClientStream newStream(final MethodDescriptor method, final M class StartCallback implements Runnable { final CronetClientStream clientStream = new CronetClientStream( url, userAgent, executor, headers, CronetClientTransport.this, this, lock, maxMessageSize, - alwaysUsePut, method, statsTraceCtx, callOptions, transportTracer); + alwaysUsePut, method, statsTraceCtx, callOptions, transportTracer, useGetForSafeMethods, + usePutForIdempotentMethods); @Override public void run() { diff --git a/cronet/src/test/java/io/grpc/cronet/CronetClientStreamTest.java b/cronet/src/test/java/io/grpc/cronet/CronetClientStreamTest.java index 3a75ebef2d6..663d5b50e4c 100644 --- a/cronet/src/test/java/io/grpc/cronet/CronetClientStreamTest.java +++ b/cronet/src/test/java/io/grpc/cronet/CronetClientStreamTest.java @@ -119,7 +119,9 @@ public void setUp() { method, StatsTraceContext.NOOP, CallOptions.DEFAULT, - transportTracer); + transportTracer, + false, + false); callback.setStream(clientStream); when(factory.newBidirectionalStreamBuilder( any(String.class), any(BidirectionalStream.Callback.class), any(Executor.class))) @@ -588,7 +590,9 @@ public void addCronetRequestAnnotation_deprecated() { method, StatsTraceContext.NOOP, CallOptions.DEFAULT.withOption(CronetClientStream.CRONET_ANNOTATION_KEY, annotation), - transportTracer); + transportTracer, + false, + false); callback.setStream(stream); when(factory.newBidirectionalStreamBuilder( any(String.class), any(BidirectionalStream.Callback.class), any(Executor.class))) @@ -621,7 +625,9 @@ public void withAnnotation() { method, StatsTraceContext.NOOP, callOptions, - transportTracer); + transportTracer, + false, + false); callback.setStream(stream); when(factory.newBidirectionalStreamBuilder( any(String.class), any(BidirectionalStream.Callback.class), any(Executor.class))) @@ -659,7 +665,9 @@ public void getUnaryRequest() { getMethod, StatsTraceContext.NOOP, CallOptions.DEFAULT, - transportTracer); + transportTracer, + true, + false); callback.setStream(stream); ExperimentalBidirectionalStream.Builder getBuilder = mock(ExperimentalBidirectionalStream.Builder.class); @@ -714,7 +722,9 @@ public void idempotentMethod_usesHttpPut() { idempotentMethod, StatsTraceContext.NOOP, CallOptions.DEFAULT, - transportTracer); + transportTracer, + true, + true); callback.setStream(stream); ExperimentalBidirectionalStream.Builder builder = mock(ExperimentalBidirectionalStream.Builder.class); @@ -744,7 +754,9 @@ public void alwaysUsePutOption_usesHttpPut() { method, StatsTraceContext.NOOP, CallOptions.DEFAULT, - transportTracer); + transportTracer, + true, + true); callback.setStream(stream); ExperimentalBidirectionalStream.Builder builder = mock(ExperimentalBidirectionalStream.Builder.class); @@ -782,7 +794,9 @@ public void reservedHeadersStripped() { method, StatsTraceContext.NOOP, CallOptions.DEFAULT, - transportTracer); + transportTracer, + false, + false); callback.setStream(stream); ExperimentalBidirectionalStream.Builder builder = mock(ExperimentalBidirectionalStream.Builder.class); diff --git a/cronet/src/test/java/io/grpc/cronet/CronetClientTransportTest.java b/cronet/src/test/java/io/grpc/cronet/CronetClientTransportTest.java index 845ba8db0e7..d00d18470ba 100644 --- a/cronet/src/test/java/io/grpc/cronet/CronetClientTransportTest.java +++ b/cronet/src/test/java/io/grpc/cronet/CronetClientTransportTest.java @@ -78,7 +78,9 @@ public void setUp() { executor, 5000, false, - TransportTracer.getDefaultFactory().create()); + TransportTracer.getDefaultFactory().create(), + false, + false); Runnable callback = transport.start(clientTransportListener); assertTrue(callback != null); callback.run(); diff --git a/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java b/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java index ae654754895..480685208f0 100644 --- a/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java +++ b/interop-testing/src/main/java/io/grpc/testing/integration/AbstractInteropTest.java @@ -371,6 +371,8 @@ public void emptyUnary() throws Exception { /** Sends a cacheable unary rpc using GET. Requires that the server is behind a caching proxy. */ public void cacheableUnary() { + // THIS TEST IS BROKEN. Enabling safe just on the MethodDescriptor does nothing by itself. This + // test would need to enable GET on the channel. // Set safe to true. MethodDescriptor safeCacheableUnaryCallMethod = TestServiceGrpc.getCacheableUnaryCallMethod().toBuilder().setSafe(true).build(); @@ -405,6 +407,7 @@ public void cacheableUnary() { assertEquals(response1, response2); assertNotEquals(response1, response3); + // THIS TEST IS BROKEN. See comment at start of method. } @Test diff --git a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java index 387a14d130a..84d47b8feee 100644 --- a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java @@ -90,6 +90,12 @@ public final class NettyChannelBuilder private ProtocolNegotiatorFactory protocolNegotiatorFactory; private LocalSocketPicker localSocketPicker; + /** + * If true, indicates that the transport may use the GET method for RPCs, and may include the + * request body in the query params. + */ + private final boolean useGetForSafeMethods = false; + /** * Creates a new builder with the given server address. This factory method is primarily intended * for using Netty Channel types other than SocketChannel. {@link #forAddress(String, int)} should @@ -415,7 +421,7 @@ protected ClientTransportFactory buildTransportFactory() { negotiator, channelFactory, channelOptions, eventLoopGroupPool, flowControlWindow, maxInboundMessageSize(), maxHeaderListSize, keepAliveTimeNanos, keepAliveTimeoutNanos, keepAliveWithoutCalls, - transportTracerFactory, localSocketPicker); + transportTracerFactory, localSocketPicker, useGetForSafeMethods); } @VisibleForTesting @@ -536,6 +542,7 @@ private static final class NettyTransportFactory implements ClientTransportFacto private final boolean keepAliveWithoutCalls; private final TransportTracer.Factory transportTracerFactory; private final LocalSocketPicker localSocketPicker; + private final boolean useGetForSafeMethods; private boolean closed; @@ -544,7 +551,8 @@ private static final class NettyTransportFactory implements ClientTransportFacto Map, ?> channelOptions, ObjectPool groupPool, int flowControlWindow, int maxMessageSize, int maxHeaderListSize, long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls, - TransportTracer.Factory transportTracerFactory, LocalSocketPicker localSocketPicker) { + TransportTracer.Factory transportTracerFactory, LocalSocketPicker localSocketPicker, + boolean useGetForSafeMethods) { this.protocolNegotiator = checkNotNull(protocolNegotiator, "protocolNegotiator"); this.channelFactory = channelFactory; this.channelOptions = new HashMap, Object>(channelOptions); @@ -559,6 +567,7 @@ private static final class NettyTransportFactory implements ClientTransportFacto this.transportTracerFactory = transportTracerFactory; this.localSocketPicker = localSocketPicker != null ? localSocketPicker : new LocalSocketPicker(); + this.useGetForSafeMethods = useGetForSafeMethods; } @Override @@ -592,7 +601,7 @@ public void run() { maxMessageSize, maxHeaderListSize, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos, keepAliveWithoutCalls, options.getAuthority(), options.getUserAgent(), tooManyPingsRunnable, transportTracerFactory.create(), options.getEagAttributes(), - localSocketPicker, channelLogger); + localSocketPicker, channelLogger, useGetForSafeMethods); return transport; } diff --git a/netty/src/main/java/io/grpc/netty/NettyClientStream.java b/netty/src/main/java/io/grpc/netty/NettyClientStream.java index c3952b43195..d0193263514 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientStream.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientStream.java @@ -75,14 +75,15 @@ class NettyClientStream extends AbstractClientStream { AsciiString userAgent, StatsTraceContext statsTraceCtx, TransportTracer transportTracer, - CallOptions callOptions) { + CallOptions callOptions, + boolean useGetForSafeMethods) { super( new NettyWritableBufferAllocator(channel.alloc()), statsTraceCtx, transportTracer, headers, callOptions, - useGet(method)); + useGetForSafeMethods && method.isSafe()); this.state = checkNotNull(state, "transportState"); this.writeQueue = state.handler.getWriteQueue(); this.method = checkNotNull(method, "method"); @@ -112,10 +113,6 @@ public Attributes getAttributes() { return state.handler.getAttributes(); } - private static boolean useGet(MethodDescriptor method) { - return method.isSafe(); - } - private class Sink implements AbstractClientStream.Sink { @Override diff --git a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java index 2577422281b..c1359d28143 100644 --- a/netty/src/main/java/io/grpc/netty/NettyClientTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyClientTransport.java @@ -100,6 +100,7 @@ class NettyClientTransport implements ConnectionClientTransport { private final Attributes eagAttributes; private final LocalSocketPicker localSocketPicker; private final ChannelLogger channelLogger; + private final boolean useGetForSafeMethods; NettyClientTransport( SocketAddress address, ChannelFactory channelFactory, @@ -108,7 +109,8 @@ class NettyClientTransport implements ConnectionClientTransport { int maxHeaderListSize, long keepAliveTimeNanos, long keepAliveTimeoutNanos, boolean keepAliveWithoutCalls, String authority, @Nullable String userAgent, Runnable tooManyPingsRunnable, TransportTracer transportTracer, Attributes eagAttributes, - LocalSocketPicker localSocketPicker, ChannelLogger channelLogger) { + LocalSocketPicker localSocketPicker, ChannelLogger channelLogger, + boolean useGetForSafeMethods) { this.negotiator = Preconditions.checkNotNull(negotiator, "negotiator"); this.negotiationScheme = this.negotiator.scheme(); this.remoteAddress = Preconditions.checkNotNull(address, "address"); @@ -131,6 +133,7 @@ class NettyClientTransport implements ConnectionClientTransport { this.localSocketPicker = Preconditions.checkNotNull(localSocketPicker, "localSocketPicker"); this.logId = InternalLogId.allocate(getClass(), remoteAddress.toString()); this.channelLogger = Preconditions.checkNotNull(channelLogger, "channelLogger"); + this.useGetForSafeMethods = useGetForSafeMethods; } @Override @@ -191,7 +194,8 @@ protected Status statusFromFailedFuture(ChannelFuture f) { userAgent, statsTraceCtx, transportTracer, - callOptions); + callOptions, + useGetForSafeMethods); } @SuppressWarnings("unchecked") diff --git a/netty/src/test/java/io/grpc/netty/NettyClientStreamTest.java b/netty/src/test/java/io/grpc/netty/NettyClientStreamTest.java index 13042f21e2d..66cb37be532 100644 --- a/netty/src/test/java/io/grpc/netty/NettyClientStreamTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyClientStreamTest.java @@ -420,7 +420,8 @@ public void setHttp2StreamShouldNotifyReady() { AsciiString.of("agent"), StatsTraceContext.NOOP, transportTracer, - CallOptions.DEFAULT); + CallOptions.DEFAULT, + false); stream.start(listener); stream().transportState().setId(STREAM_ID); verify(listener, never()).onReady(); @@ -450,7 +451,8 @@ public void removeUserAgentFromApplicationHeaders() { AsciiString.of("good agent"), StatsTraceContext.NOOP, transportTracer, - CallOptions.DEFAULT); + CallOptions.DEFAULT, + false); stream.start(listener); ArgumentCaptor cmdCap = ArgumentCaptor.forClass(CreateStreamCommand.class); @@ -480,7 +482,8 @@ public void getRequestSentThroughHeader() { AsciiString.of("agent"), StatsTraceContext.NOOP, transportTracer, - CallOptions.DEFAULT); + CallOptions.DEFAULT, + true); stream.start(listener); stream.transportState().setId(STREAM_ID); stream.transportState().setHttp2Stream(http2Stream); @@ -513,7 +516,8 @@ protected NettyClientStream createStream() { AsciiString.of("agent"), StatsTraceContext.NOOP, transportTracer, - CallOptions.DEFAULT); + CallOptions.DEFAULT, + false); stream.start(listener); stream.transportState().setHttp2Stream(http2Stream); reset(listener); diff --git a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java index ea46bac159a..dc1a4b99105 100644 --- a/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyClientTransportTest.java @@ -193,7 +193,7 @@ public void setSoLingerChannelOption() throws IOException { newNegotiator(), DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, KEEPALIVE_TIME_NANOS_DISABLED, 1L, false, authority, null /* user agent */, tooManyPingsRunnable, new TransportTracer(), Attributes.EMPTY, - new SocketPicker(), new FakeChannelLogger()); + new SocketPicker(), new FakeChannelLogger(), false); transports.add(transport); callMeMaybe(transport.start(clientTransportListener)); @@ -439,7 +439,7 @@ public void failingToConstructChannelShouldFailGracefully() throws Exception { newNegotiator(), DEFAULT_WINDOW_SIZE, DEFAULT_MAX_MESSAGE_SIZE, GrpcUtil.DEFAULT_MAX_HEADER_LIST_SIZE, KEEPALIVE_TIME_NANOS_DISABLED, 1, false, authority, null, tooManyPingsRunnable, new TransportTracer(), Attributes.EMPTY, new SocketPicker(), - new FakeChannelLogger()); + new FakeChannelLogger(), false); transports.add(transport); // Should not throw @@ -709,7 +709,7 @@ private NettyClientTransport newTransport(ProtocolNegotiator negotiator, int max negotiator, DEFAULT_WINDOW_SIZE, maxMsgSize, maxHeaderListSize, keepAliveTimeNano, keepAliveTimeoutNano, false, authority, userAgent, tooManyPingsRunnable, - new TransportTracer(), eagAttributes, new SocketPicker(), new FakeChannelLogger()); + new TransportTracer(), eagAttributes, new SocketPicker(), new FakeChannelLogger(), false); transports.add(transport); return transport; } diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java index 85f81b889f7..b8071d9cf62 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java @@ -129,6 +129,12 @@ public static OkHttpChannelBuilder forTarget(String target) { private boolean keepAliveWithoutCalls; private int maxInboundMetadataSize = Integer.MAX_VALUE; + /** + * If true, indicates that the transport may use the GET method for RPCs, and may include the + * request body in the query params. + */ + private final boolean useGetForSafeMethods = true; + protected OkHttpChannelBuilder(String host, int port) { this(GrpcUtil.authorityFromHostAndPort(host, port)); } @@ -391,7 +397,8 @@ protected final ClientTransportFactory buildTransportFactory() { flowControlWindow, keepAliveWithoutCalls, maxInboundMetadataSize, - transportTracerFactory); + transportTracerFactory, + useGetForSafeMethods); } @Override @@ -449,6 +456,7 @@ static final class OkHttpTransportFactory implements ClientTransportFactory { private final boolean keepAliveWithoutCalls; private final int maxInboundMetadataSize; private final ScheduledExecutorService timeoutService; + private final boolean useGetForSafeMethods; private boolean closed; private OkHttpTransportFactory( @@ -465,7 +473,8 @@ private OkHttpTransportFactory( int flowControlWindow, boolean keepAliveWithoutCalls, int maxInboundMetadataSize, - TransportTracer.Factory transportTracerFactory) { + TransportTracer.Factory transportTracerFactory, + boolean useGetForSafeMethods) { usingSharedScheduler = timeoutService == null; this.timeoutService = usingSharedScheduler ? SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE) : timeoutService; @@ -480,6 +489,7 @@ private OkHttpTransportFactory( this.flowControlWindow = flowControlWindow; this.keepAliveWithoutCalls = keepAliveWithoutCalls; this.maxInboundMetadataSize = maxInboundMetadataSize; + this.useGetForSafeMethods = useGetForSafeMethods; usingSharedExecutor = executor == null; this.transportTracerFactory = @@ -522,7 +532,8 @@ public void run() { options.getHttpConnectProxiedSocketAddress(), tooManyPingsRunnable, maxInboundMetadataSize, - transportTracerFactory.create()); + transportTracerFactory.create(), + useGetForSafeMethods); if (enableKeepAlive) { transport.enableKeepAlive( true, keepAliveTimeNanosState.get(), keepAliveTimeoutNanos, keepAliveWithoutCalls); diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java index 66f4f875461..2a474faa3a9 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java @@ -74,14 +74,15 @@ class OkHttpClientStream extends AbstractClientStream { String userAgent, StatsTraceContext statsTraceCtx, TransportTracer transportTracer, - CallOptions callOptions) { + CallOptions callOptions, + boolean useGetForSafeMethods) { super( new OkHttpWritableBufferAllocator(), statsTraceCtx, transportTracer, headers, callOptions, - method.isSafe()); + useGetForSafeMethods && method.isSafe()); this.statsTraceCtx = checkNotNull(statsTraceCtx, "statsTraceCtx"); this.method = method; this.authority = authority; diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java index 698d4afeb91..6244cab6f3e 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java @@ -198,6 +198,7 @@ private static Map buildErrorCodeToStatusMap() { private boolean keepAliveWithoutCalls; private final Runnable tooManyPingsRunnable; private final int maxInboundMetadataSize; + private final boolean useGetForSafeMethods; @GuardedBy("lock") private final TransportTracer transportTracer; @GuardedBy("lock") @@ -239,7 +240,8 @@ protected void handleNotInUse() { @Nullable HttpConnectProxiedSocketAddress proxiedAddr, Runnable tooManyPingsRunnable, int maxInboundMetadataSize, - TransportTracer transportTracer) { + TransportTracer transportTracer, + boolean useGetForSafeMethods) { this.address = Preconditions.checkNotNull(address, "address"); this.defaultAuthority = authority; this.maxMessageSize = maxMessageSize; @@ -263,6 +265,7 @@ protected void handleNotInUse() { this.logId = InternalLogId.allocate(getClass(), address.toString()); this.attributes = Attributes.newBuilder() .set(GrpcAttributes.ATTR_CLIENT_EAG_ATTRS, eagAttrs).build(); + this.useGetForSafeMethods = useGetForSafeMethods; initTransportTracer(); } @@ -285,6 +288,7 @@ protected void handleNotInUse() { int initialWindowSize, Runnable tooManyPingsRunnable, TransportTracer transportTracer) { + useGetForSafeMethods = false; address = null; this.maxMessageSize = maxMessageSize; this.initialWindowSize = initialWindowSize; @@ -397,7 +401,8 @@ public OkHttpClientStream newStream(final MethodDescriptor method, userAgent, statsTraceCtx, transportTracer, - callOptions); + callOptions, + useGetForSafeMethods); } } diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java index ac8bf46fc63..8d613026aa6 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java @@ -99,7 +99,8 @@ public void setUp() { "userAgent", StatsTraceContext.NOOP, transportTracer, - CallOptions.DEFAULT); + CallOptions.DEFAULT, + false); } @Test @@ -158,7 +159,7 @@ public void start_userAgentRemoved() throws IOException { metaData.put(GrpcUtil.USER_AGENT_KEY, "misbehaving-application"); stream = new OkHttpClientStream(methodDescriptor, metaData, frameWriter, transport, flowController, lock, MAX_MESSAGE_SIZE, INITIAL_WINDOW_SIZE, "localhost", - "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT); + "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT, false); stream.start(new BaseClientStreamListener()); stream.transportState().start(3); @@ -174,7 +175,7 @@ public void start_headerFieldOrder() throws IOException { metaData.put(GrpcUtil.USER_AGENT_KEY, "misbehaving-application"); stream = new OkHttpClientStream(methodDescriptor, metaData, frameWriter, transport, flowController, lock, MAX_MESSAGE_SIZE, INITIAL_WINDOW_SIZE, "localhost", - "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT); + "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT, false); stream.start(new BaseClientStreamListener()); stream.transportState().start(3); @@ -203,7 +204,7 @@ public void getUnaryRequest() throws IOException { .build(); stream = new OkHttpClientStream(getMethod, new Metadata(), frameWriter, transport, flowController, lock, MAX_MESSAGE_SIZE, INITIAL_WINDOW_SIZE, "localhost", - "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT); + "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT, true); stream.start(new BaseClientStreamListener()); // GET streams send headers after halfClose is called. diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java index 4c5fb21ff73..b2a63763b76 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java @@ -264,7 +264,8 @@ public void testToString() throws Exception { NO_PROXY, tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - transportTracer); + transportTracer, + false); String s = clientTransport.toString(); assertTrue("Unexpected: " + s, s.contains("OkHttpClientTransport")); assertTrue("Unexpected: " + s, s.contains(address.toString())); @@ -1664,7 +1665,8 @@ public void invalidAuthorityPropagates() { NO_PROXY, tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - transportTracer); + transportTracer, + false); String host = clientTransport.getOverridenHost(); int port = clientTransport.getOverridenPort(); @@ -1690,7 +1692,8 @@ public void unreachableServer() throws Exception { NO_PROXY, tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - new TransportTracer()); + new TransportTracer(), + false); ManagedClientTransport.Listener listener = mock(ManagedClientTransport.Listener.class); clientTransport.start(listener); @@ -1727,7 +1730,8 @@ public void customSocketFactory() throws Exception { NO_PROXY, tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - new TransportTracer()); + new TransportTracer(), + false); ManagedClientTransport.Listener listener = mock(ManagedClientTransport.Listener.class); clientTransport.start(listener); @@ -1759,7 +1763,8 @@ public void proxy_200() throws Exception { .setProxyAddress(serverSocket.getLocalSocketAddress()).build(), tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - transportTracer); + transportTracer, + false); clientTransport.start(transportListener); Socket sock = serverSocket.accept(); @@ -1815,7 +1820,8 @@ public void proxy_500() throws Exception { .setProxyAddress(serverSocket.getLocalSocketAddress()).build(), tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - transportTracer); + transportTracer, + false); clientTransport.start(transportListener); Socket sock = serverSocket.accept(); @@ -1870,7 +1876,8 @@ public void proxy_immediateServerClose() throws Exception { .setProxyAddress(serverSocket.getLocalSocketAddress()).build(), tooManyPingsRunnable, DEFAULT_MAX_INBOUND_METADATA_SIZE, - transportTracer); + transportTracer, + false); clientTransport.start(transportListener); Socket sock = serverSocket.accept(); From 4ec5be387edf51738350885f8107d65134c3c329 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Wed, 25 Sep 2019 16:40:09 -0700 Subject: [PATCH 036/131] Update README etc to reference 1.24.0 (#6197) --- README.md | 28 ++++++++++++------------ documentation/android-channel-builder.md | 4 ++-- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d995ddd617e..2b2e5e30384 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ For a guided tour, take a look at the [quick start guide](https://grpc.io/docs/quickstart/java.html) or the more explanatory [gRPC basics](https://grpc.io/docs/tutorials/basic/java.html). -The [examples](https://github.com/grpc/grpc-java/tree/v1.23.0/examples) and the -[Android example](https://github.com/grpc/grpc-java/tree/v1.23.0/examples/android) +The [examples](https://github.com/grpc/grpc-java/tree/v1.24.0/examples) and the +[Android example](https://github.com/grpc/grpc-java/tree/v1.24.0/examples/android) are standalone projects that showcase the usage of gRPC. Download @@ -42,37 +42,37 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: io.grpc grpc-netty-shaded - 1.23.0 + 1.24.0 io.grpc grpc-protobuf - 1.23.0 + 1.24.0 io.grpc grpc-stub - 1.23.0 + 1.24.0 ``` Or for Gradle with non-Android, add to your dependencies: ```gradle -implementation 'io.grpc:grpc-netty-shaded:1.23.0' -implementation 'io.grpc:grpc-protobuf:1.23.0' -implementation 'io.grpc:grpc-stub:1.23.0' +implementation 'io.grpc:grpc-netty-shaded:1.24.0' +implementation 'io.grpc:grpc-protobuf:1.24.0' +implementation 'io.grpc:grpc-stub:1.24.0' ``` For Android client, use `grpc-okhttp` instead of `grpc-netty-shaded` and `grpc-protobuf-lite` instead of `grpc-protobuf`: ```gradle -implementation 'io.grpc:grpc-okhttp:1.23.0' -implementation 'io.grpc:grpc-protobuf-lite:1.23.0' -implementation 'io.grpc:grpc-stub:1.23.0' +implementation 'io.grpc:grpc-okhttp:1.24.0' +implementation 'io.grpc:grpc-protobuf-lite:1.24.0' +implementation 'io.grpc:grpc-stub:1.24.0' ``` [the JARs]: -https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.23.0 +https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.24.0 Development snapshots are available in [Sonatypes's snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/). @@ -104,7 +104,7 @@ For protobuf-based codegen integrated with the Maven build system, you can use com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier} grpc-java - io.grpc:protoc-gen-grpc-java:1.23.0:exe:${os.detected.classifier} + io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier} @@ -134,7 +134,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.23.0' + artifact = 'io.grpc:protoc-gen-grpc-java:1.24.0' } } generateProtoTasks { diff --git a/documentation/android-channel-builder.md b/documentation/android-channel-builder.md index de204fd9f68..eb006c3c361 100644 --- a/documentation/android-channel-builder.md +++ b/documentation/android-channel-builder.md @@ -36,8 +36,8 @@ In your `build.gradle` file, include a dependency on both `grpc-android` and `grpc-okhttp`: ``` -implementation 'io.grpc:grpc-android:1.23.0' -implementation 'io.grpc:grpc-okhttp:1.23.0' +implementation 'io.grpc:grpc-android:1.24.0' +implementation 'io.grpc:grpc-okhttp:1.24.0' ``` You will also need permission to access the device's network state in your From e67fdb3af9850c7bb6d822da6ca1c54acd380732 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 26 Sep 2019 14:21:18 -0700 Subject: [PATCH 037/131] github: wrap question template in comment blocks (#6199) --- .github/ISSUE_TEMPLATE/ask_question.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/ask_question.md b/.github/ISSUE_TEMPLATE/ask_question.md index 573a0d55e69..6e69a0a86a6 100644 --- a/.github/ISSUE_TEMPLATE/ask_question.md +++ b/.github/ISSUE_TEMPLATE/ask_question.md @@ -4,9 +4,9 @@ about: Asking a question related gRPC-Java labels: question --- -For questions not directly related to gRPC-Java, please use [stackoverflow](https://stackoverflow.com/questions/tagged/grpc-java). + -[[Your question here]] + From 68eba768c91dcb13f41ddd06f7d7a845cd0901ab Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Thu, 26 Sep 2019 15:27:47 -0700 Subject: [PATCH 038/131] cronet: do not include internal accessors in Javadoc (#6205) --- cronet/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/cronet/build.gradle b/cronet/build.gradle index 38c1db1df87..a5505083f39 100644 --- a/cronet/build.gradle +++ b/cronet/build.gradle @@ -79,6 +79,7 @@ task javadocs(type: Javadoc) { addStringOption('Xdoclint:none', '-quiet') } } + exclude 'io/grpc/cronet/Internal*' } task javadocJar(type: Jar, dependsOn: javadocs) { From e3be6a6bfad77378a680b97b2499c3b1de17888b Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Fri, 27 Sep 2019 09:22:42 -0700 Subject: [PATCH 039/131] compiler: add license header for cpp codes (#6208) --- compiler/src/java_plugin/cpp/java_generator.cpp | 16 ++++++++++++++++ compiler/src/java_plugin/cpp/java_generator.h | 16 ++++++++++++++++ compiler/src/java_plugin/cpp/java_plugin.cpp | 16 ++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp index 8110f3d55f2..c4c69b5e251 100644 --- a/compiler/src/java_plugin/cpp/java_generator.cpp +++ b/compiler/src/java_plugin/cpp/java_generator.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #include "java_generator.h" #include diff --git a/compiler/src/java_plugin/cpp/java_generator.h b/compiler/src/java_plugin/cpp/java_generator.h index 7e2c1a8fe0a..41a7fc093ff 100644 --- a/compiler/src/java_plugin/cpp/java_generator.h +++ b/compiler/src/java_plugin/cpp/java_generator.h @@ -1,3 +1,19 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + #ifndef NET_GRPC_COMPILER_JAVA_GENERATOR_H_ #define NET_GRPC_COMPILER_JAVA_GENERATOR_H_ diff --git a/compiler/src/java_plugin/cpp/java_plugin.cpp b/compiler/src/java_plugin/cpp/java_plugin.cpp index fff219177ee..098a4db2178 100644 --- a/compiler/src/java_plugin/cpp/java_plugin.cpp +++ b/compiler/src/java_plugin/cpp/java_plugin.cpp @@ -1,3 +1,19 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + // Generates Java gRPC service interface out of Protobuf IDL. // // This is a Proto2 compiler plugin. See net/proto2/compiler/proto/plugin.proto From 214eaae3bab8dec1bb6141fea9cd09b67d0b2590 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Fri, 27 Sep 2019 11:10:47 -0700 Subject: [PATCH 040/131] android-interop-testing: remove settings for using GET via setting MethodDescriptor to safe (#6203) * Removed client interceptor that sets safe in method descriptor. * Removed useGet checkbox in UI. --- .../android/integrationtest/InteropTask.java | 14 ++------- .../integrationtest/TesterActivity.java | 30 +------------------ .../src/main/res/layout/activity_tester.xml | 5 ---- .../app/src/main/res/values/strings.xml | 1 - 4 files changed, 3 insertions(+), 47 deletions(-) diff --git a/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/InteropTask.java b/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/InteropTask.java index d1d181df28c..caeafb723d9 100644 --- a/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/InteropTask.java +++ b/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/InteropTask.java @@ -18,13 +18,11 @@ import android.os.AsyncTask; import android.util.Log; -import io.grpc.ClientInterceptor; import io.grpc.ManagedChannel; import io.grpc.testing.integration.AbstractInteropTest; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.ref.WeakReference; -import java.util.List; import org.junit.AssumptionViolatedException; /** AsyncTask for interop test cases. */ @@ -44,11 +42,10 @@ interface Listener { InteropTask( Listener listener, ManagedChannel channel, - List interceptors, String testCase) { this.listenerReference = new WeakReference(listener); this.testCase = testCase; - this.tester = new Tester(channel, interceptors); + this.tester = new Tester(channel); } @Override @@ -149,11 +146,9 @@ protected void onPostExecute(String result) { private static class Tester extends AbstractInteropTest { private final ManagedChannel channel; - private final List interceptors; - private Tester(ManagedChannel channel, List interceptors) { + private Tester(ManagedChannel channel) { this.channel = channel; - this.interceptors = interceptors; } @Override @@ -161,11 +156,6 @@ protected ManagedChannel createChannel() { return channel; } - @Override - protected ClientInterceptor[] getAdditionalInterceptors() { - return interceptors.toArray(new ClientInterceptor[0]); - } - @Override protected boolean metricsExpected() { return false; diff --git a/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/TesterActivity.java b/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/TesterActivity.java index e365f048e51..4081439f239 100644 --- a/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/TesterActivity.java +++ b/android-interop-testing/app/src/main/java/io/grpc/android/integrationtest/TesterActivity.java @@ -29,16 +29,8 @@ import android.widget.EditText; import android.widget.TextView; import com.google.android.gms.security.ProviderInstaller; -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.ClientCall; -import io.grpc.ClientInterceptor; -import io.grpc.ClientInterceptors.CheckedForwardingClientCall; import io.grpc.ManagedChannel; -import io.grpc.Metadata; -import io.grpc.MethodDescriptor; import java.io.InputStream; -import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -50,7 +42,6 @@ public class TesterActivity extends AppCompatActivity private EditText hostEdit; private EditText portEdit; private TextView resultText; - private CheckBox getCheckBox; private CheckBox testCertCheckBox; @Override @@ -67,7 +58,6 @@ protected void onCreate(Bundle savedInstanceState) { hostEdit = (EditText) findViewById(R.id.host_edit_text); portEdit = (EditText) findViewById(R.id.port_edit_text); resultText = (TextView) findViewById(R.id.grpc_response_text); - getCheckBox = (CheckBox) findViewById(R.id.get_checkbox); testCertCheckBox = (CheckBox) findViewById(R.id.test_cert_checkbox); ProviderInstaller.installIfNeededAsync(this, this); @@ -129,11 +119,7 @@ private void startTest(String testCase) { ManagedChannel channel = TesterOkHttpChannelBuilder.build(host, port, serverHostOverride, true, testCert); - List interceptors = new ArrayList<>(); - if (getCheckBox.isChecked()) { - interceptors.add(new SafeMethodChannelInterceptor()); - } - new InteropTask(this, channel, interceptors, testCase).execute(); + new InteropTask(this, channel, testCase).execute(); } @Override @@ -149,18 +135,4 @@ public void onProviderInstallFailed(int errorCode, Intent recoveryIntent) { Log.w(LOG_TAG, "Failed installing security provider, error code: " + errorCode); enableButtons(true); } - - private static final class SafeMethodChannelInterceptor implements ClientInterceptor { - @Override - public ClientCall interceptCall( - MethodDescriptor method, CallOptions callOptions, Channel next) { - return new CheckedForwardingClientCall( - next.newCall(method.toBuilder().setSafe(true).build(), callOptions)) { - @Override - public void checkedStart(Listener responseListener, Metadata headers) { - delegate().start(responseListener, headers); - } - }; - } - } } diff --git a/android-interop-testing/app/src/main/res/layout/activity_tester.xml b/android-interop-testing/app/src/main/res/layout/activity_tester.xml index 1fd55dd835a..f1339330227 100644 --- a/android-interop-testing/app/src/main/res/layout/activity_tester.xml +++ b/android-interop-testing/app/src/main/res/layout/activity_tester.xml @@ -33,11 +33,6 @@ android:layout_height="wrap_content" android:orientation="horizontal" > - gRPC Integration Test - Use GET From 7435221629472ecda373b9d9e8648b5b93a5adfd Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Fri, 27 Sep 2019 11:21:58 -0700 Subject: [PATCH 041/131] Make grpc-xds dependent on grpc-netty - needed for TLS related protocolNegotiator implementations in grpc-xds (#6206) --- xds/build.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/xds/build.gradle b/xds/build.gradle index 8d5423aec44..67902d17d53 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -20,6 +20,7 @@ dependencies { compile project(':grpc-protobuf'), project(':grpc-stub'), project(':grpc-core'), + project(':grpc-netty'), project(':grpc-services'), project(':grpc-auth') compile (libraries.pgv) { @@ -73,6 +74,8 @@ shadowJar { relocate 'com.github.udpa', 'io.grpc.xds.shaded.com.github.udpa' relocate 'com.google.protobuf.GoGoProtos', 'io.grpc.xds.shaded.gogoproto.GoGoProtos' relocate 'io.envoyproxy', 'io.grpc.xds.shaded.io.envoyproxy' + relocate 'io.grpc.netty', 'io.grpc.netty.shaded.io.grpc.netty' + relocate 'io.netty', 'io.grpc.netty.shaded.io.netty' exclude "**/*.proto" } @@ -81,6 +84,17 @@ publishing { maven(MavenPublication) { artifact shadowJar artifacts.removeAll { it.classifier == 'original' } + + pom.withXml { + // Swap our dependency to grpc-netty-shaded. Projects depending on this via + // project(':grpc-xds') will still be using the non-shaded form. + asNode().dependencies.'*'.findAll() { dep -> + dep.artifactId.text() == 'grpc-netty' + }.each() { netty -> + netty.artifactId*.value = 'grpc-netty-shaded' + netty.version*.value = "[" + netty.version.text() + "]" + } + } } } } From d3e86da6b61f93be81f5f807a0b1cef1c035cff0 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Fri, 27 Sep 2019 11:45:38 -0700 Subject: [PATCH 042/131] core: move generic Json util methods out of ServiceConfigUtil (#6211) --- .../io/grpc/internal/DnsNameResolver.java | 8 +- .../main/java/io/grpc/internal/JsonUtil.java | 118 +++++++++++++ .../io/grpc/internal/ServiceConfigUtil.java | 155 ++++-------------- 3 files changed, 155 insertions(+), 126 deletions(-) create mode 100644 core/src/main/java/io/grpc/internal/JsonUtil.java diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolver.java b/core/src/main/java/io/grpc/internal/DnsNameResolver.java index cd3611c705e..6555c98b37e 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolver.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolver.java @@ -461,7 +461,7 @@ private static final Double getPercentageFromChoice(Map serviceConfig if (!serviceConfigChoice.containsKey(SERVICE_CONFIG_CHOICE_PERCENTAGE_KEY)) { return null; } - return ServiceConfigUtil.getDouble(serviceConfigChoice, SERVICE_CONFIG_CHOICE_PERCENTAGE_KEY); + return JsonUtil.getDouble(serviceConfigChoice, SERVICE_CONFIG_CHOICE_PERCENTAGE_KEY); } @Nullable @@ -471,7 +471,7 @@ private static final List getClientLanguagesFromChoice( return null; } return ServiceConfigUtil.checkStringList( - ServiceConfigUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_LANGUAGE_KEY)); + JsonUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_LANGUAGE_KEY)); } @Nullable @@ -480,7 +480,7 @@ private static final List getHostnamesFromChoice(Map serviceC return null; } return ServiceConfigUtil.checkStringList( - ServiceConfigUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_HOSTNAME_KEY)); + JsonUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_HOSTNAME_KEY)); } /** @@ -559,7 +559,7 @@ private static long getNetworkAddressCacheTtlNanos(boolean isAndroid) { } } Map sc = - ServiceConfigUtil.getObject(choice, SERVICE_CONFIG_CHOICE_SERVICE_CONFIG_KEY); + JsonUtil.getObject(choice, SERVICE_CONFIG_CHOICE_SERVICE_CONFIG_KEY); if (sc == null) { throw new VerifyException(String.format( "key '%s' missing in '%s'", choice, SERVICE_CONFIG_CHOICE_SERVICE_CONFIG_KEY)); diff --git a/core/src/main/java/io/grpc/internal/JsonUtil.java b/core/src/main/java/io/grpc/internal/JsonUtil.java new file mode 100644 index 00000000000..876d354bb35 --- /dev/null +++ b/core/src/main/java/io/grpc/internal/JsonUtil.java @@ -0,0 +1,118 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.internal; + +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; + +/** + * Helper utility to work with JSON values in Java types. + */ +public class JsonUtil { + /** + * Gets a list from an object for the given key. If the key is not present, this returns null. + * If the value is not a List, throws an exception. + */ + @SuppressWarnings("unchecked") + @Nullable + public static List getList(Map obj, String key) { + assert key != null; + if (!obj.containsKey(key)) { + return null; + } + Object value = obj.get(key); + if (!(value instanceof List)) { + throw new ClassCastException( + String.format("value '%s' for key '%s' in '%s' is not List", value, key, obj)); + } + return (List) value; + } + + /** + * Gets an object from an object for the given key. If the key is not present, this returns null. + * If the value is not a Map, throws an exception. + */ + @SuppressWarnings("unchecked") + @Nullable + public static Map getObject(Map obj, String key) { + assert key != null; + if (!obj.containsKey(key)) { + return null; + } + Object value = obj.get(key); + if (!(value instanceof Map)) { + throw new ClassCastException( + String.format("value '%s' for key '%s' in '%s' is not object", value, key, obj)); + } + return (Map) value; + } + + /** + * Gets a double from an object for the given key. If the key is not present, this returns null. + * If the value is not a Double, throws an exception. + */ + @Nullable + public static Double getDouble(Map obj, String key) { + assert key != null; + if (!obj.containsKey(key)) { + return null; + } + Object value = obj.get(key); + if (!(value instanceof Double)) { + throw new ClassCastException( + String.format("value '%s' for key '%s' in '%s' is not Double", value, key, obj)); + } + return (Double) value; + } + + /** + * Gets a string from an object for the given key. If the key is not present, this returns null. + * If the value is not a String, throws an exception. + */ + @Nullable + public static String getString(Map obj, String key) { + assert key != null; + if (!obj.containsKey(key)) { + return null; + } + Object value = obj.get(key); + if (!(value instanceof String)) { + throw new ClassCastException( + String.format("value '%s' for key '%s' in '%s' is not String", value, key, obj)); + } + return (String) value; + } + + /** + * Gets a boolean from an object for the given key. If the key is not present, this returns null. + * If the value is not a Boolean, throws an exception. + */ + @Nullable + public static Boolean getBoolean(Map obj, String key) { + assert key != null; + if (!obj.containsKey(key)) { + return null; + } + Object value = obj.get(key); + if (!(value instanceof Boolean)) { + throw new ClassCastException( + String.format("value '%s' for key '%s' in '%s' is not Boolean", value, key, obj)); + } + return (Boolean) value; + } +} diff --git a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java index b8289d24026..303378880b7 100644 --- a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java +++ b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java @@ -96,11 +96,11 @@ public static String getHealthCheckedServiceName(@Nullable Map servic } } */ - Map healthCheck = getObject(serviceConfig, healthCheckKey); + Map healthCheck = JsonUtil.getObject(serviceConfig, healthCheckKey); if (!healthCheck.containsKey(serviceNameKey)) { return null; } - return getString(healthCheck, "serviceName"); + return JsonUtil.getString(healthCheck, "serviceName"); } @Nullable @@ -129,11 +129,11 @@ static Throttle getThrottlePolicy(@Nullable Map serviceConfig) { } */ - Map throttling = getObject(serviceConfig, retryThrottlingKey); + Map throttling = JsonUtil.getObject(serviceConfig, retryThrottlingKey); // TODO(dapengzhang0): check if this is null. - float maxTokens = getDouble(throttling, "maxTokens").floatValue(); - float tokenRatio = getDouble(throttling, "tokenRatio").floatValue(); + float maxTokens = JsonUtil.getDouble(throttling, "maxTokens").floatValue(); + float tokenRatio = JsonUtil.getDouble(throttling, "tokenRatio").floatValue(); checkState(maxTokens > 0f, "maxToken should be greater than zero"); checkState(tokenRatio > 0f, "tokenRatio should be greater than zero"); return new Throttle(maxTokens, tokenRatio); @@ -144,7 +144,7 @@ static Integer getMaxAttemptsFromRetryPolicy(Map retryPolicy) { if (!retryPolicy.containsKey(RETRY_POLICY_MAX_ATTEMPTS_KEY)) { return null; } - return getDouble(retryPolicy, RETRY_POLICY_MAX_ATTEMPTS_KEY).intValue(); + return JsonUtil.getDouble(retryPolicy, RETRY_POLICY_MAX_ATTEMPTS_KEY).intValue(); } @Nullable @@ -152,7 +152,7 @@ static Long getInitialBackoffNanosFromRetryPolicy(Map retryPolicy) { if (!retryPolicy.containsKey(RETRY_POLICY_INITIAL_BACKOFF_KEY)) { return null; } - String rawInitialBackoff = getString(retryPolicy, RETRY_POLICY_INITIAL_BACKOFF_KEY); + String rawInitialBackoff = JsonUtil.getString(retryPolicy, RETRY_POLICY_INITIAL_BACKOFF_KEY); try { return parseDuration(rawInitialBackoff); } catch (ParseException e) { @@ -165,7 +165,7 @@ static Long getMaxBackoffNanosFromRetryPolicy(Map retryPolicy) { if (!retryPolicy.containsKey(RETRY_POLICY_MAX_BACKOFF_KEY)) { return null; } - String rawMaxBackoff = getString(retryPolicy, RETRY_POLICY_MAX_BACKOFF_KEY); + String rawMaxBackoff = JsonUtil.getString(retryPolicy, RETRY_POLICY_MAX_BACKOFF_KEY); try { return parseDuration(rawMaxBackoff); } catch (ParseException e) { @@ -178,7 +178,7 @@ static Double getBackoffMultiplierFromRetryPolicy(Map retryPolicy) { if (!retryPolicy.containsKey(RETRY_POLICY_BACKOFF_MULTIPLIER_KEY)) { return null; } - return getDouble(retryPolicy, RETRY_POLICY_BACKOFF_MULTIPLIER_KEY); + return JsonUtil.getDouble(retryPolicy, RETRY_POLICY_BACKOFF_MULTIPLIER_KEY); } private static Set getStatusCodesFromList(List statuses) { @@ -212,7 +212,8 @@ static Set getRetryableStatusCodesFromRetryPolicy(Map re retryPolicy.containsKey(RETRY_POLICY_RETRYABLE_STATUS_CODES_KEY), "%s is required in retry policy", RETRY_POLICY_RETRYABLE_STATUS_CODES_KEY); Set codes = - getStatusCodesFromList(getList(retryPolicy, RETRY_POLICY_RETRYABLE_STATUS_CODES_KEY)); + getStatusCodesFromList( + JsonUtil.getList(retryPolicy, RETRY_POLICY_RETRYABLE_STATUS_CODES_KEY)); verify(!codes.isEmpty(), "%s must not be empty", RETRY_POLICY_RETRYABLE_STATUS_CODES_KEY); verify( !codes.contains(Status.Code.OK), @@ -225,7 +226,7 @@ static Integer getMaxAttemptsFromHedgingPolicy(Map hedgingPolicy) { if (!hedgingPolicy.containsKey(HEDGING_POLICY_MAX_ATTEMPTS_KEY)) { return null; } - return getDouble(hedgingPolicy, HEDGING_POLICY_MAX_ATTEMPTS_KEY).intValue(); + return JsonUtil.getDouble(hedgingPolicy, HEDGING_POLICY_MAX_ATTEMPTS_KEY).intValue(); } @Nullable @@ -233,7 +234,7 @@ static Long getHedgingDelayNanosFromHedgingPolicy(Map hedgingPolicy) if (!hedgingPolicy.containsKey(HEDGING_POLICY_HEDGING_DELAY_KEY)) { return null; } - String rawHedgingDelay = getString(hedgingPolicy, HEDGING_POLICY_HEDGING_DELAY_KEY); + String rawHedgingDelay = JsonUtil.getString(hedgingPolicy, HEDGING_POLICY_HEDGING_DELAY_KEY); try { return parseDuration(rawHedgingDelay); } catch (ParseException e) { @@ -246,7 +247,8 @@ static Set getNonFatalStatusCodesFromHedgingPolicy(Map h return Collections.unmodifiableSet(EnumSet.noneOf(Status.Code.class)); } Set codes = - getStatusCodesFromList(getList(hedgingPolicy, HEDGING_POLICY_NON_FATAL_STATUS_CODES_KEY)); + getStatusCodesFromList( + JsonUtil.getList(hedgingPolicy, HEDGING_POLICY_NON_FATAL_STATUS_CODES_KEY)); verify( !codes.contains(Status.Code.OK), "%s must not contain OK", HEDGING_POLICY_NON_FATAL_STATUS_CODES_KEY); @@ -258,7 +260,7 @@ static String getServiceFromName(Map name) { if (!name.containsKey(NAME_SERVICE_KEY)) { return null; } - return getString(name, NAME_SERVICE_KEY); + return JsonUtil.getString(name, NAME_SERVICE_KEY); } @Nullable @@ -266,7 +268,7 @@ static String getMethodFromName(Map name) { if (!name.containsKey(NAME_METHOD_KEY)) { return null; } - return getString(name, NAME_METHOD_KEY); + return JsonUtil.getString(name, NAME_METHOD_KEY); } @Nullable @@ -274,7 +276,7 @@ static String getMethodFromName(Map name) { if (!methodConfig.containsKey(METHOD_CONFIG_RETRY_POLICY_KEY)) { return null; } - return getObject(methodConfig, METHOD_CONFIG_RETRY_POLICY_KEY); + return JsonUtil.getObject(methodConfig, METHOD_CONFIG_RETRY_POLICY_KEY); } @Nullable @@ -282,7 +284,7 @@ static String getMethodFromName(Map name) { if (!methodConfig.containsKey(METHOD_CONFIG_HEDGING_POLICY_KEY)) { return null; } - return getObject(methodConfig, METHOD_CONFIG_HEDGING_POLICY_KEY); + return JsonUtil.getObject(methodConfig, METHOD_CONFIG_HEDGING_POLICY_KEY); } @Nullable @@ -291,7 +293,7 @@ static String getMethodFromName(Map name) { if (!methodConfig.containsKey(METHOD_CONFIG_NAME_KEY)) { return null; } - return checkObjectList(getList(methodConfig, METHOD_CONFIG_NAME_KEY)); + return checkObjectList(JsonUtil.getList(methodConfig, METHOD_CONFIG_NAME_KEY)); } /** @@ -304,7 +306,7 @@ static Long getTimeoutFromMethodConfig(Map methodConfig) { if (!methodConfig.containsKey(METHOD_CONFIG_TIMEOUT_KEY)) { return null; } - String rawTimeout = getString(methodConfig, METHOD_CONFIG_TIMEOUT_KEY); + String rawTimeout = JsonUtil.getString(methodConfig, METHOD_CONFIG_TIMEOUT_KEY); try { return parseDuration(rawTimeout); } catch (ParseException e) { @@ -317,7 +319,7 @@ static Boolean getWaitForReadyFromMethodConfig(Map methodConfig) { if (!methodConfig.containsKey(METHOD_CONFIG_WAIT_FOR_READY_KEY)) { return null; } - return getBoolean(methodConfig, METHOD_CONFIG_WAIT_FOR_READY_KEY); + return JsonUtil.getBoolean(methodConfig, METHOD_CONFIG_WAIT_FOR_READY_KEY); } @Nullable @@ -325,7 +327,7 @@ static Integer getMaxRequestMessageBytesFromMethodConfig(Map methodCo if (!methodConfig.containsKey(METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES_KEY)) { return null; } - return getDouble(methodConfig, METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES_KEY).intValue(); + return JsonUtil.getDouble(methodConfig, METHOD_CONFIG_MAX_REQUEST_MESSAGE_BYTES_KEY).intValue(); } @Nullable @@ -333,7 +335,8 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC if (!methodConfig.containsKey(METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES_KEY)) { return null; } - return getDouble(methodConfig, METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES_KEY).intValue(); + return JsonUtil.getDouble(methodConfig, METHOD_CONFIG_MAX_RESPONSE_MESSAGE_BYTES_KEY) + .intValue(); } @Nullable @@ -342,7 +345,7 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC if (!serviceConfig.containsKey(SERVICE_CONFIG_METHOD_CONFIG_KEY)) { return null; } - return checkObjectList(getList(serviceConfig, SERVICE_CONFIG_METHOD_CONFIG_KEY)); + return checkObjectList(JsonUtil.getList(serviceConfig, SERVICE_CONFIG_METHOD_CONFIG_KEY)); } /** @@ -369,7 +372,7 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC */ List> lbConfigs = new ArrayList<>(); if (serviceConfig.containsKey(SERVICE_CONFIG_LOAD_BALANCING_CONFIG_KEY)) { - List configs = getList(serviceConfig, SERVICE_CONFIG_LOAD_BALANCING_CONFIG_KEY); + List configs = JsonUtil.getList(serviceConfig, SERVICE_CONFIG_LOAD_BALANCING_CONFIG_KEY); for (Map config : checkObjectList(configs)) { lbConfigs.add(config); } @@ -378,7 +381,7 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC // No LoadBalancingConfig found. Fall back to the deprecated LoadBalancingPolicy if (serviceConfig.containsKey(SERVICE_CONFIG_LOAD_BALANCING_POLICY_KEY)) { // TODO(zhangkun83): check if this is null. - String policy = getString(serviceConfig, SERVICE_CONFIG_LOAD_BALANCING_POLICY_KEY); + String policy = JsonUtil.getString(serviceConfig, SERVICE_CONFIG_LOAD_BALANCING_POLICY_KEY); // Convert the policy to a config, so that the caller can handle them in the same way. policy = policy.toLowerCase(Locale.ROOT); Map fakeConfig = Collections.singletonMap(policy, Collections.emptyMap()); @@ -401,7 +404,7 @@ public static LbConfig unwrapLoadBalancingConfig(Map lbConfig) { + " is expected. Config=" + lbConfig); } String key = lbConfig.entrySet().iterator().next().getKey(); - return new LbConfig(key, getObject(lbConfig, key)); + return new LbConfig(key, JsonUtil.getObject(lbConfig, key)); } /** @@ -420,7 +423,7 @@ public static List unwrapLoadBalancingConfigList(List> * Extracts the loadbalancer name from xds loadbalancer config. */ public static String getBalancerNameFromXdsConfig(Map rawXdsConfig) { - return getString(rawXdsConfig, XDS_CONFIG_BALANCER_NAME_KEY); + return JsonUtil.getString(rawXdsConfig, XDS_CONFIG_BALANCER_NAME_KEY); } /** @@ -428,7 +431,7 @@ public static String getBalancerNameFromXdsConfig(Map rawXdsConfig) { */ @Nullable public static List getChildPolicyFromXdsConfig(Map rawXdsConfig) { - List rawChildPolicies = getList(rawXdsConfig, XDS_CONFIG_CHILD_POLICY_KEY); + List rawChildPolicies = JsonUtil.getList(rawXdsConfig, XDS_CONFIG_CHILD_POLICY_KEY); if (rawChildPolicies != null) { return unwrapLoadBalancingConfigList(checkObjectList(rawChildPolicies)); } @@ -440,7 +443,7 @@ public static List getChildPolicyFromXdsConfig(Map rawXdsCo */ @Nullable public static List getFallbackPolicyFromXdsConfig(Map rawXdsConfig) { - List rawFallbackPolicies = getList(rawXdsConfig, XDS_CONFIG_FALLBACK_POLICY_KEY); + List rawFallbackPolicies = JsonUtil.getList(rawXdsConfig, XDS_CONFIG_FALLBACK_POLICY_KEY); if (rawFallbackPolicies != null) { return unwrapLoadBalancingConfigList(checkObjectList(rawFallbackPolicies)); } @@ -456,99 +459,7 @@ public static String getStickinessMetadataKeyFromServiceConfig( if (!serviceConfig.containsKey(SERVICE_CONFIG_STICKINESS_METADATA_KEY)) { return null; } - return getString(serviceConfig, SERVICE_CONFIG_STICKINESS_METADATA_KEY); - } - - /** - * Gets a list from an object for the given key. If the key is not present, this returns null. - * If the value is not a List, throws an exception. - */ - @SuppressWarnings("unchecked") - @Nullable - static List getList(Map obj, String key) { - assert key != null; - if (!obj.containsKey(key)) { - return null; - } - Object value = obj.get(key); - if (!(value instanceof List)) { - throw new ClassCastException( - String.format("value '%s' for key '%s' in '%s' is not List", value, key, obj)); - } - return (List) value; - } - - /** - * Gets an object from an object for the given key. If the key is not present, this returns null. - * If the value is not a List, throws an exception. - */ - @SuppressWarnings("unchecked") - @Nullable - static Map getObject(Map obj, String key) { - assert key != null; - if (!obj.containsKey(key)) { - return null; - } - Object value = obj.get(key); - if (!(value instanceof Map)) { - throw new ClassCastException( - String.format("value '%s' for key '%s' in '%s' is not object", value, key, obj)); - } - return (Map) value; - } - - /** - * Gets a double from an object for the given key. If the key is not present, this returns null. - * If the value is not a Double, throws an exception. - */ - @Nullable - static Double getDouble(Map obj, String key) { - assert key != null; - if (!obj.containsKey(key)) { - return null; - } - Object value = obj.get(key); - if (!(value instanceof Double)) { - throw new ClassCastException( - String.format("value '%s' for key '%s' in '%s' is not Double", value, key, obj)); - } - return (Double) value; - } - - /** - * Gets a string from an object for the given key. If the key is not present, this returns null. - * If the value is not a String, throws an exception. - */ - @Nullable - static String getString(Map obj, String key) { - assert key != null; - if (!obj.containsKey(key)) { - return null; - } - Object value = obj.get(key); - if (!(value instanceof String)) { - throw new ClassCastException( - String.format("value '%s' for key '%s' in '%s' is not String", value, key, obj)); - } - return (String) value; - } - - /** - * Gets a boolean from an object for the given key. If the key is not present, this returns null. - * If the value is not a Boolean, throws an exception. - */ - @Nullable - static Boolean getBoolean(Map obj, String key) { - assert key != null; - if (!obj.containsKey(key)) { - return null; - } - Object value = obj.get(key); - if (!(value instanceof Boolean)) { - throw new ClassCastException( - String.format("value '%s' for key '%s' in '%s' is not Boolean", value, key, obj)); - } - return (Boolean) value; + return JsonUtil.getString(serviceConfig, SERVICE_CONFIG_STICKINESS_METADATA_KEY); } @SuppressWarnings("unchecked") From 18a9671ea00229d37d43dabf3bd8d165c06389b0 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Fri, 27 Sep 2019 14:29:26 -0700 Subject: [PATCH 043/131] core: move check Json object methods to JsonUtil (#6214) --- .../io/grpc/internal/DnsNameResolver.java | 6 ++-- .../main/java/io/grpc/internal/JsonUtil.java | 31 +++++++++++++++++ .../io/grpc/internal/ServiceConfigUtil.java | 34 ++++--------------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolver.java b/core/src/main/java/io/grpc/internal/DnsNameResolver.java index 6555c98b37e..0da09299afa 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolver.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolver.java @@ -451,7 +451,7 @@ static ResolutionResults resolveAll( throw new ClassCastException("wrong type " + rawChoices); } List listChoices = (List) rawChoices; - possibleServiceConfigChoices.addAll(ServiceConfigUtil.checkObjectList(listChoices)); + possibleServiceConfigChoices.addAll(JsonUtil.checkObjectList(listChoices)); } return possibleServiceConfigChoices; } @@ -470,7 +470,7 @@ private static final List getClientLanguagesFromChoice( if (!serviceConfigChoice.containsKey(SERVICE_CONFIG_CHOICE_CLIENT_LANGUAGE_KEY)) { return null; } - return ServiceConfigUtil.checkStringList( + return JsonUtil.checkStringList( JsonUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_LANGUAGE_KEY)); } @@ -479,7 +479,7 @@ private static final List getHostnamesFromChoice(Map serviceC if (!serviceConfigChoice.containsKey(SERVICE_CONFIG_CHOICE_CLIENT_HOSTNAME_KEY)) { return null; } - return ServiceConfigUtil.checkStringList( + return JsonUtil.checkStringList( JsonUtil.getList(serviceConfigChoice, SERVICE_CONFIG_CHOICE_CLIENT_HOSTNAME_KEY)); } diff --git a/core/src/main/java/io/grpc/internal/JsonUtil.java b/core/src/main/java/io/grpc/internal/JsonUtil.java index 876d354bb35..d25698c635b 100644 --- a/core/src/main/java/io/grpc/internal/JsonUtil.java +++ b/core/src/main/java/io/grpc/internal/JsonUtil.java @@ -115,4 +115,35 @@ public static Boolean getBoolean(Map obj, String key) { } return (Boolean) value; } + + /** + * Casts a list of unchecked JSON values to a list of checked objects in Java type. + * If the given list contains a value that is not a Map, throws an exception. + */ + @SuppressWarnings("unchecked") + public static List> checkObjectList(List rawList) { + for (int i = 0; i < rawList.size(); i++) { + if (!(rawList.get(i) instanceof Map)) { + throw new ClassCastException( + String.format("value %s for idx %d in %s is not object", rawList.get(i), i, rawList)); + } + } + return (List>) rawList; + } + + /** + * Casts a list of unchecked JSON values to a list of String. If the given list + * contains a value that is not a String, throws an exception. + */ + @SuppressWarnings("unchecked") + public static List checkStringList(List rawList) { + for (int i = 0; i < rawList.size(); i++) { + if (!(rawList.get(i) instanceof String)) { + throw new ClassCastException( + String.format( + "value '%s' for idx %d in '%s' is not string", rawList.get(i), i, rawList)); + } + } + return (List) rawList; + } } diff --git a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java index 303378880b7..0f4318a9aab 100644 --- a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java +++ b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java @@ -293,7 +293,7 @@ static String getMethodFromName(Map name) { if (!methodConfig.containsKey(METHOD_CONFIG_NAME_KEY)) { return null; } - return checkObjectList(JsonUtil.getList(methodConfig, METHOD_CONFIG_NAME_KEY)); + return JsonUtil.checkObjectList(JsonUtil.getList(methodConfig, METHOD_CONFIG_NAME_KEY)); } /** @@ -345,7 +345,8 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC if (!serviceConfig.containsKey(SERVICE_CONFIG_METHOD_CONFIG_KEY)) { return null; } - return checkObjectList(JsonUtil.getList(serviceConfig, SERVICE_CONFIG_METHOD_CONFIG_KEY)); + return JsonUtil + .checkObjectList(JsonUtil.getList(serviceConfig, SERVICE_CONFIG_METHOD_CONFIG_KEY)); } /** @@ -373,7 +374,7 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC List> lbConfigs = new ArrayList<>(); if (serviceConfig.containsKey(SERVICE_CONFIG_LOAD_BALANCING_CONFIG_KEY)) { List configs = JsonUtil.getList(serviceConfig, SERVICE_CONFIG_LOAD_BALANCING_CONFIG_KEY); - for (Map config : checkObjectList(configs)) { + for (Map config : JsonUtil.checkObjectList(configs)) { lbConfigs.add(config); } } @@ -433,7 +434,7 @@ public static String getBalancerNameFromXdsConfig(Map rawXdsConfig) { public static List getChildPolicyFromXdsConfig(Map rawXdsConfig) { List rawChildPolicies = JsonUtil.getList(rawXdsConfig, XDS_CONFIG_CHILD_POLICY_KEY); if (rawChildPolicies != null) { - return unwrapLoadBalancingConfigList(checkObjectList(rawChildPolicies)); + return unwrapLoadBalancingConfigList(JsonUtil.checkObjectList(rawChildPolicies)); } return null; } @@ -445,7 +446,7 @@ public static List getChildPolicyFromXdsConfig(Map rawXdsCo public static List getFallbackPolicyFromXdsConfig(Map rawXdsConfig) { List rawFallbackPolicies = JsonUtil.getList(rawXdsConfig, XDS_CONFIG_FALLBACK_POLICY_KEY); if (rawFallbackPolicies != null) { - return unwrapLoadBalancingConfigList(checkObjectList(rawFallbackPolicies)); + return unwrapLoadBalancingConfigList(JsonUtil.checkObjectList(rawFallbackPolicies)); } return null; } @@ -462,29 +463,6 @@ public static String getStickinessMetadataKeyFromServiceConfig( return JsonUtil.getString(serviceConfig, SERVICE_CONFIG_STICKINESS_METADATA_KEY); } - @SuppressWarnings("unchecked") - static List> checkObjectList(List rawList) { - for (int i = 0; i < rawList.size(); i++) { - if (!(rawList.get(i) instanceof Map)) { - throw new ClassCastException( - String.format("value %s for idx %d in %s is not object", rawList.get(i), i, rawList)); - } - } - return (List>) rawList; - } - - @SuppressWarnings("unchecked") - static List checkStringList(List rawList) { - for (int i = 0; i < rawList.size(); i++) { - if (!(rawList.get(i) instanceof String)) { - throw new ClassCastException( - String.format( - "value '%s' for idx %d in '%s' is not string", rawList.get(i), i, rawList)); - } - } - return (List) rawList; - } - /** * Parse from a string to produce a duration. Copy of * {@link com.google.protobuf.util.Durations#parse}. From 5afba81806f0b5d507e121cf4b838b556978903b Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Fri, 27 Sep 2019 11:05:56 -0700 Subject: [PATCH 044/131] build: add mavenCentral to repositories --- build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle b/build.gradle index a4dff88d0cc..c44f8d81755 100644 --- a/build.gradle +++ b/build.gradle @@ -22,6 +22,7 @@ subprojects { repositories { maven { // The google mirror is less flaky than mavenCentral() url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } + mavenCentral() mavenLocal() } From 15295c75aea3503a4fce3a61b91aaae7b3a1d865 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Fri, 27 Sep 2019 11:18:58 -0700 Subject: [PATCH 045/131] examples: add mavenCentral build.gradle without jcenter repo --- examples/build.gradle | 1 + examples/example-gauth/build.gradle | 1 + examples/example-tls/build.gradle | 1 + 3 files changed, 3 insertions(+) diff --git a/examples/build.gradle b/examples/build.gradle index 4af94892c22..76113892d4b 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -10,6 +10,7 @@ plugins { repositories { maven { // The google mirror is less flaky than mavenCentral() url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } + mavenCentral() mavenLocal() } diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index ea782b269e7..c10fa437596 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -11,6 +11,7 @@ repositories { maven { // The google mirror is less flaky than mavenCentral() url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } + mavenCentral() mavenLocal() } diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index ab70b0a797e..f169a8e587f 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -11,6 +11,7 @@ repositories { maven { // The google mirror is less flaky than mavenCentral() url "https://maven-central.storage-download.googleapis.com/repos/central/data/" } + mavenCentral() mavenLocal() } From 3f11b27a2281249891aa4e8cfc7776adba93412d Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 26 Sep 2019 19:43:04 -0700 Subject: [PATCH 046/131] alts: make AltsHandshakerClient#close can be called multiple times --- .../java/io/grpc/alts/internal/AltsHandshakerClient.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/alts/src/main/java/io/grpc/alts/internal/AltsHandshakerClient.java b/alts/src/main/java/io/grpc/alts/internal/AltsHandshakerClient.java index 7ed197ef5bf..e9103963780 100644 --- a/alts/src/main/java/io/grpc/alts/internal/AltsHandshakerClient.java +++ b/alts/src/main/java/io/grpc/alts/internal/AltsHandshakerClient.java @@ -229,8 +229,14 @@ public ByteBuffer next(ByteBuffer inBytes) throws GeneralSecurityException { return resp.getOutFrames().asReadOnlyByteBuffer(); } + private boolean closed = false; + /** Closes the connection. */ public void close() { + if (closed) { + return; + } + closed = true; handshakerStub.close(); } } From caf54fb66f413d57a14e82e4fc2f7d4929d69dd2 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Mon, 30 Sep 2019 10:03:54 -0700 Subject: [PATCH 047/131] bom: format(tab->space) build.gradle --- bom/build.gradle | 50 ++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/bom/build.gradle b/bom/build.gradle index dd22c7e7ae5..12598bc523d 100644 --- a/bom/build.gradle +++ b/bom/build.gradle @@ -1,36 +1,36 @@ plugins { - id "maven-publish" + id "maven-publish" } description = 'gRPC: BOM' publishing { - publications { - maven(MavenPublication) { - // remove all other artifacts since BOM doesn't generates any Jar - artifacts = [] + publications { + maven(MavenPublication) { + // remove all other artifacts since BOM doesn't generates any Jar + artifacts = [] - pom.withXml { - // Generate bom using subprojects - def internalProjects = [project.name, 'grpc-xds', 'grpc-gae-interop-testing-jdk8', 'grpc-compiler'] + pom.withXml { + // Generate bom using subprojects + def internalProjects = [project.name, 'grpc-xds', 'grpc-gae-interop-testing-jdk8', 'grpc-compiler'] - def dependencyManagement = asNode().appendNode('dependencyManagement') - def dependencies = dependencyManagement.appendNode('dependencies') - rootProject.subprojects.each { subproject -> - if (internalProjects.contains(subproject.name)) { - return - } - def dependencyNode = dependencies.appendNode('dependency') - dependencyNode.appendNode('groupId', subproject.group) - dependencyNode.appendNode('artifactId', subproject.name) - dependencyNode.appendNode('version', subproject.version) - } - // add protoc gen (produced by grpc-compiler with different artifact name) - def dependencyNode = dependencies.appendNode('dependency') - dependencyNode.appendNode('groupId', project.group) - dependencyNode.appendNode('artifactId', 'protoc-gen-grpc-java') - dependencyNode.appendNode('version', project.version) - } + def dependencyManagement = asNode().appendNode('dependencyManagement') + def dependencies = dependencyManagement.appendNode('dependencies') + rootProject.subprojects.each { subproject -> + if (internalProjects.contains(subproject.name)) { + return + } + def dependencyNode = dependencies.appendNode('dependency') + dependencyNode.appendNode('groupId', subproject.group) + dependencyNode.appendNode('artifactId', subproject.name) + dependencyNode.appendNode('version', subproject.version) } + // add protoc gen (produced by grpc-compiler with different artifact name) + def dependencyNode = dependencies.appendNode('dependency') + dependencyNode.appendNode('groupId', project.group) + dependencyNode.appendNode('artifactId', 'protoc-gen-grpc-java') + dependencyNode.appendNode('version', project.version) + } } + } } From a8137dc18f39151d2e0addb61735bb7579d2062e Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Mon, 30 Sep 2019 10:05:49 -0700 Subject: [PATCH 048/131] bom: specify pom type for protoc-gen-grpc-java --- bom/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/bom/build.gradle b/bom/build.gradle index 12598bc523d..67914432227 100644 --- a/bom/build.gradle +++ b/bom/build.gradle @@ -30,6 +30,7 @@ publishing { dependencyNode.appendNode('groupId', project.group) dependencyNode.appendNode('artifactId', 'protoc-gen-grpc-java') dependencyNode.appendNode('version', project.version) + dependencyNode.appendNode('type', 'pom') } } } From 0be86a5731b48920174fe97a661262737c6b9e66 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 30 Sep 2019 13:39:22 -0700 Subject: [PATCH 049/131] alts: Use Conscrypt when available We depend on Conscrypt to help ensure Conscrypt 2.1.0 or newer is used. It's not 100% clear this is the best approach, but it is the simplest at present. If Conscrypt is not available then we will just use the JDK's slower implementation of AES-GCM. Fixes #6213 --- alts/build.gradle | 6 +- .../grpc/alts/internal/AesGcmAeadCrypter.java | 62 ++++++++++++++++++- .../internal/ChannelCrypterNettyTestBase.java | 10 +-- .../java/io/grpc/alts/internal/TsiTest.java | 10 +-- build.gradle | 2 +- .../io/grpc/internal/testing/TestUtils.java | 14 +++++ 6 files changed, 89 insertions(+), 15 deletions(-) diff --git a/alts/build.gradle b/alts/build.gradle index 79db7949614..84130c20398 100644 --- a/alts/build.gradle +++ b/alts/build.gradle @@ -19,7 +19,8 @@ dependencies { project(':grpc-protobuf'), project(':grpc-stub'), libraries.lang, - libraries.protobuf + libraries.protobuf, + libraries.conscrypt compile (libraries.google_auth_oauth2_http) { // prefer 26.0-android from libraries instead of 25.1-android exclude group: 'com.google.guava', module: 'guava' @@ -36,8 +37,7 @@ dependencies { libraries.mockito, libraries.truth testRuntime libraries.netty_tcnative, - libraries.netty_epoll, - libraries.conscrypt + libraries.netty_epoll signature 'org.codehaus.mojo.signature:java17:1.0@signature' } diff --git a/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java b/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java index f3b968f1312..3e0bf2f84b4 100644 --- a/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java +++ b/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java @@ -18,8 +18,12 @@ import static com.google.common.base.Preconditions.checkArgument; +import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; +import java.security.Provider; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.annotation.Nullable; import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; @@ -27,12 +31,15 @@ /** AES128-GCM implementation of {@link AeadCrypter} that uses default JCE provider. */ final class AesGcmAeadCrypter implements AeadCrypter { + private static final Logger logger = Logger.getLogger(AesGcmAeadCrypter.class.getName()); private static final int KEY_LENGTH = 16; private static final int TAG_LENGTH = 16; static final int NONCE_LENGTH = 12; private static final String AES = "AES"; private static final String AES_GCM = AES + "/GCM/NoPadding"; + // Conscrypt if available, otherwise null. Conscrypt is much faster than Java 8's JSSE + private static final Provider CONSCRYPT = getConscrypt(); private final byte[] key; private final Cipher cipher; @@ -40,7 +47,11 @@ final class AesGcmAeadCrypter implements AeadCrypter { AesGcmAeadCrypter(byte[] key) throws GeneralSecurityException { checkArgument(key.length == KEY_LENGTH); this.key = key; - cipher = Cipher.getInstance(AES_GCM); + if (CONSCRYPT != null) { + cipher = Cipher.getInstance(AES_GCM, CONSCRYPT); + } else { + cipher = Cipher.getInstance(AES_GCM); + } } private int encryptAad( @@ -98,4 +109,53 @@ public void decrypt(ByteBuffer plaintext, ByteBuffer ciphertext, ByteBuffer aad, static int getKeyLength() { return KEY_LENGTH; } + + private static Provider getConscrypt() { + // This is equivalent to if (Conscrypt.isAvailable()) return Conscrypt.newProvider(); + + // Conscrypt 2.1.0 or later is required. If an older version is used, it will fail with these + // sorts of errors: + // "The underlying Cipher implementation does not support this method" + // "error:1e000067:Cipher functions:OPENSSL_internal:BUFFER_TOO_SMALL" + // + // While we could use Conscrypt.version() to check compatibility, that is _very_ verbose via + // reflection. In practice, old conscrypts are probably not much of a problem. + Class conscryptClass; + try { + conscryptClass = Class.forName("org.conscrypt.Conscrypt"); + } catch (ClassNotFoundException ex) { + logger.log(Level.FINE, "Could not find Conscrypt", ex); + return null; + } + Method method; + try { + method = conscryptClass.getMethod("newProvider"); + } catch (SecurityException ex) { + logger.log(Level.FINE, "Could not find Conscrypt factory method", ex); + return null; + } catch (NoSuchMethodException ex) { + logger.log(Level.WARNING, "Could not find Conscrypt factory method", ex); + return null; + } + Object provider; + try { + provider = method.invoke(null); + } catch (IllegalAccessException ex) { + logger.log(Level.WARNING, "Could not call Conscrypt factory method", ex); + return null; + } catch (Throwable ex) { + // This is probably an InvocationTargetException, which means something's wrong with the JNI + // loading. Maybe the platform is not supported. We could have used Conscrypt.isAvailable(), + // but it just catches Throwable as well + logger.log(Level.WARNING, "Failed calling Conscrypt factory method", ex); + return null; + } + if (!(provider instanceof Provider)) { + logger.log( + Level.WARNING, "Could not load Conscrypt. Returned provider was not a Provider: {0}", + provider.getClass().getName()); + return null; + } + return (Provider) provider; + } } diff --git a/alts/src/test/java/io/grpc/alts/internal/ChannelCrypterNettyTestBase.java b/alts/src/test/java/io/grpc/alts/internal/ChannelCrypterNettyTestBase.java index 6de3c59671c..cab0765e7d7 100644 --- a/alts/src/test/java/io/grpc/alts/internal/ChannelCrypterNettyTestBase.java +++ b/alts/src/test/java/io/grpc/alts/internal/ChannelCrypterNettyTestBase.java @@ -35,7 +35,7 @@ /** Abstract class for unit tests of {@link ChannelCrypterNetty}. */ public abstract class ChannelCrypterNettyTestBase { - private static final String DECRYPTION_FAILURE_MESSAGE = "Tag mismatch"; + private static final String DECRYPTION_FAILURE_MESSAGE_RE = "Tag mismatch|BAD_DECRYPT"; protected final List references = new ArrayList<>(); public ChannelCrypterNetty client; @@ -169,7 +169,7 @@ public void reflection() throws GeneralSecurityException { client.decrypt(frameDecrypt.out, frameDecrypt.tag, frameDecrypt.ciphertext); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_MESSAGE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_MESSAGE_RE); } } @@ -186,7 +186,7 @@ public void skipMessage() throws GeneralSecurityException { client.decrypt(frameDecrypt.out, frameDecrypt.tag, frameDecrypt.ciphertext); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_MESSAGE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_MESSAGE_RE); } } @@ -202,7 +202,7 @@ public void corruptMessage() throws GeneralSecurityException { client.decrypt(frameDecrypt.out, frameDecrypt.tag, frameDecrypt.ciphertext); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_MESSAGE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_MESSAGE_RE); } } @@ -220,7 +220,7 @@ public void replayMessage() throws GeneralSecurityException { server.decrypt(frameDecrypt2.out, frameDecrypt2.tag, frameDecrypt2.ciphertext); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_MESSAGE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_MESSAGE_RE); } } } diff --git a/alts/src/test/java/io/grpc/alts/internal/TsiTest.java b/alts/src/test/java/io/grpc/alts/internal/TsiTest.java index 5c9cf265e25..5182ecde028 100644 --- a/alts/src/test/java/io/grpc/alts/internal/TsiTest.java +++ b/alts/src/test/java/io/grpc/alts/internal/TsiTest.java @@ -35,7 +35,7 @@ /** Utility class that provides tests for implementations of @{link TsiHandshaker}. */ public final class TsiTest { - private static final String DECRYPTION_FAILURE_RE = "Tag mismatch!"; + private static final String DECRYPTION_FAILURE_RE = "Tag mismatch!|BAD_DECRYPT"; private TsiTest() {} @@ -282,7 +282,7 @@ public void accept(ByteBuf buf) { receiver.unprotect(protect, unprotectOut, alloc); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_RE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_RE); } sender.destroy(); @@ -321,7 +321,7 @@ public void accept(ByteBuf buf) { receiver.unprotect(protect, unprotectOut, alloc); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_RE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_RE); } sender.destroy(); @@ -360,7 +360,7 @@ public void accept(ByteBuf buf) { receiver.unprotect(protect, unprotectOut, alloc); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_RE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_RE); } sender.destroy(); @@ -396,7 +396,7 @@ public void accept(ByteBuf buf) { sender.unprotect(protect.slice(), unprotectOut, alloc); fail("Exception expected"); } catch (AEADBadTagException ex) { - assertThat(ex).hasMessageThat().contains(DECRYPTION_FAILURE_RE); + assertThat(ex).hasMessageThat().containsMatch(DECRYPTION_FAILURE_RE); } sender.destroy(); diff --git a/build.gradle b/build.gradle index c44f8d81755..bcecc1e3331 100644 --- a/build.gradle +++ b/build.gradle @@ -152,7 +152,7 @@ subprojects { // examples/example-tls/pom.xml netty_tcnative: 'io.netty:netty-tcnative-boringssl-static:2.0.25.Final', - conscrypt: 'org.conscrypt:conscrypt-openjdk-uber:1.0.1', + conscrypt: 'org.conscrypt:conscrypt-openjdk-uber:2.2.1', re2j: 'com.google.re2j:re2j:1.2', // Test dependencies. diff --git a/testing/src/main/java/io/grpc/internal/testing/TestUtils.java b/testing/src/main/java/io/grpc/internal/testing/TestUtils.java index f9d8d7ba5da..f80f6a763ab 100644 --- a/testing/src/main/java/io/grpc/internal/testing/TestUtils.java +++ b/testing/src/main/java/io/grpc/internal/testing/TestUtils.java @@ -16,6 +16,7 @@ package io.grpc.internal.testing; +import com.google.common.base.Throwables; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -156,6 +157,12 @@ public static void installConscryptIfAvailable() { if (conscryptInstallAttempted) { return; } + // Conscrypt-based I/O (like used in OkHttp) breaks on Windows. + // https://github.com/google/conscrypt/issues/444 + if (System.mapLibraryName("test").endsWith(".dll")) { + conscryptInstallAttempted = true; + return; + } Class conscrypt; try { conscrypt = Class.forName("org.conscrypt.Conscrypt"); @@ -175,6 +182,13 @@ public static void installConscryptIfAvailable() { } catch (IllegalAccessException ex) { throw new RuntimeException("Could not invoke Conscrypt.newProvider", ex); } catch (InvocationTargetException ex) { + Throwable root = Throwables.getRootCause(ex); + // Conscrypt uses a newer version of glibc than available on RHEL 6 + if (root instanceof UnsatisfiedLinkError && root.getMessage() != null + && root.getMessage().contains("GLIBC_2.14")) { + conscryptInstallAttempted = true; + return; + } throw new RuntimeException("Could not invoke Conscrypt.newProvider", ex); } Security.addProvider(provider); From 65b495c6bcfab3f74f0904421017fc5098e0e9f0 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 30 Sep 2019 11:39:25 -0700 Subject: [PATCH 050/131] benchmarks: Remove unnecessary unchecked casts --- .../java/io/grpc/benchmarks/TransportBenchmark.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java b/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java index b00ace790ec..de151264ac4 100644 --- a/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java +++ b/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java @@ -123,16 +123,16 @@ public void setUp() throws Exception { Class groupClass = Class.forName("io.netty.channel.epoll.EpollEventLoopGroup"); EventLoopGroup group = (EventLoopGroup) groupClass.getConstructor().newInstance(); - @SuppressWarnings("unchecked") - Class serverChannelClass = (Class) - Class.forName("io.netty.channel.epoll.EpollServerSocketChannel"); + Class serverChannelClass = + Class.forName("io.netty.channel.epoll.EpollServerSocketChannel") + .asSubclass(ServerChannel.class); serverBuilder = NettyServerBuilder.forAddress(address) .bossEventLoopGroup(group) .workerEventLoopGroup(group) .channelType(serverChannelClass); - @SuppressWarnings("unchecked") - Class channelClass = (Class) - Class.forName("io.netty.channel.epoll.EpollSocketChannel"); + Class channelClass = + Class.forName("io.netty.channel.epoll.EpollSocketChannel") + .asSubclass(Channel.class); channelBuilder = NettyChannelBuilder.forAddress(address) .eventLoopGroup(group) .channelType(channelClass) From ad159cea965f2ebec939dc50521272fe3e26f86e Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 30 Sep 2019 11:31:56 -0700 Subject: [PATCH 051/131] Remove vestigial SuppressWarnings("LiteralClassName") Error Prone 2.1.2 removed the warning. --- .../src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java | 1 - benchmarks/src/main/java/io/grpc/benchmarks/qps/AsyncServer.java | 1 - .../main/java/io/grpc/internal/JndiResourceResolverFactory.java | 1 - 3 files changed, 3 deletions(-) diff --git a/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java b/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java index de151264ac4..9f01b5e9143 100644 --- a/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java +++ b/benchmarks/src/jmh/java/io/grpc/benchmarks/TransportBenchmark.java @@ -79,7 +79,6 @@ public enum Transport { private EventLoopGroup groupToShutdown; @Setup - @SuppressWarnings("LiteralClassName") // Epoll is not available on windows public void setUp() throws Exception { AbstractServerImplBuilder serverBuilder; AbstractManagedChannelImplBuilder channelBuilder; diff --git a/benchmarks/src/main/java/io/grpc/benchmarks/qps/AsyncServer.java b/benchmarks/src/main/java/io/grpc/benchmarks/qps/AsyncServer.java index 87ee508a30f..cd165c74988 100644 --- a/benchmarks/src/main/java/io/grpc/benchmarks/qps/AsyncServer.java +++ b/benchmarks/src/main/java/io/grpc/benchmarks/qps/AsyncServer.java @@ -89,7 +89,6 @@ public void run() { server.awaitTermination(); } - @SuppressWarnings("LiteralClassName") // Epoll is not available on windows static Server newServer(ServerConfiguration config) throws IOException { final EventLoopGroup boss; final EventLoopGroup worker; diff --git a/core/src/main/java/io/grpc/internal/JndiResourceResolverFactory.java b/core/src/main/java/io/grpc/internal/JndiResourceResolverFactory.java index 35db1b05d0c..518393b43be 100644 --- a/core/src/main/java/io/grpc/internal/JndiResourceResolverFactory.java +++ b/core/src/main/java/io/grpc/internal/JndiResourceResolverFactory.java @@ -62,7 +62,6 @@ public JndiResourceResolverFactory() {} * may not actually be used to perform the query. This is believed to be "okay." */ @Nullable - @SuppressWarnings("LiteralClassName") private static Throwable initJndi() { try { Class.forName("javax.naming.directory.InitialDirContext"); From 881594100bdd75d46b4dde1a8cafb858a0bc2b56 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Mon, 30 Sep 2019 15:26:01 -0700 Subject: [PATCH 052/131] andriod-interop-testing: fix InteropTask construction failure with wrong parameters (#6223) --- .../android/integrationtest/InteropInstrumentationTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/android-interop-testing/app/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java b/android-interop-testing/app/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java index 47f6fc72dd4..e6a2c85fda5 100644 --- a/android-interop-testing/app/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java +++ b/android-interop-testing/app/src/androidTest/java/io/grpc/android/integrationtest/InteropInstrumentationTest.java @@ -26,10 +26,8 @@ import com.google.android.gms.common.GooglePlayServicesRepairableException; import com.google.android.gms.security.ProviderInstaller; import com.google.common.util.concurrent.SettableFuture; -import io.grpc.ClientInterceptor; import io.grpc.android.integrationtest.InteropTask.Listener; import java.io.InputStream; -import java.util.ArrayList; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Rule; @@ -127,7 +125,6 @@ public void onComplete(String result) { new InteropTask( listener, TesterOkHttpChannelBuilder.build(host, port, serverHostOverride, useTls, testCa), - new ArrayList(), testCase) .execute(); String result = resultFuture.get(TIMEOUT_SECONDS, TimeUnit.SECONDS); From c5c7755d3fe9d84ec2d87e277a49ea15a3e9cba6 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 1 Oct 2019 09:03:43 -0700 Subject: [PATCH 053/131] repositories.bzl: Fix typo in maven_install override_targets The typo was present in the initial version added in 9d6f532 --- repositories.bzl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/repositories.bzl b/repositories.bzl index 82f7a59a77c..f963f85c39d 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -26,7 +26,7 @@ IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS = { "io.grpc:grpc-api": "@io_grpc_grpc_java//api", "io.grpc:grpc-auth": "@io_grpc_grpc_java//auth", "io.grpc:grpc-context": "@io_grpc_grpc_java//context", - "io.grpc:grpc-core": "@io_grpc_grpc_java//core_maven", + "io.grpc:grpc-core": "@io_grpc_grpc_java//core:core_maven", "io.grpc:grpc-grpclb": "@io_grpc_grpc_java//grpclb", "io.grpc:grpc-netty": "@io_grpc_grpc_java//netty", "io.grpc:grpc-netty-shaded": "@io_grpc_grpc_java//netty:shaded_maven", From 9668102f05a10a5b386ff8ddde470ae8a8a22fae Mon Sep 17 00:00:00 2001 From: Przemek Piotrowski Date: Tue, 1 Oct 2019 22:41:06 +0200 Subject: [PATCH 054/131] netty: bump to 4.1.42 (#6175) netty: bump to 4.1.42 --- SECURITY.md | 3 +- build.gradle | 4 +-- examples/example-tls/build.gradle | 2 +- repositories.bzl | 48 +++++++++++++++---------------- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index d31ca6c0dc2..304a33efb41 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -395,7 +395,8 @@ grpc-netty version | netty-handler version | netty-tcnative-boringssl-static ver 1.18.x-1.19.x | 4.1.32.Final | 2.0.20.Final 1.20.x-1.21.x | 4.1.34.Final | 2.0.22.Final 1.22.x | 4.1.35.Final | 2.0.25.Final -1.23.x- | 4.1.38.Final | 2.0.25.Final +1.23.x-1.24.x | 4.1.38.Final | 2.0.25.Final +1.25.x- | 4.1.42.Final | 2.0.26.Final _(grpc-netty-shaded avoids issues with keeping these versions in sync.)_ diff --git a/build.gradle b/build.gradle index bcecc1e3331..6d8ff89425e 100644 --- a/build.gradle +++ b/build.gradle @@ -44,7 +44,7 @@ subprojects { protocPluginBaseName = 'protoc-gen-grpc-java' javaPluginPath = "$rootDir/compiler/build/exe/java_plugin/$protocPluginBaseName$exeSuffix" - nettyVersion = '4.1.38.Final' + nettyVersion = '4.1.42.Final' guavaVersion = '28.1-android' googleauthVersion = '0.17.1' protobufVersion = '3.9.0' @@ -150,7 +150,7 @@ subprojects { // SECURITY.md (multiple occurrences) // examples/example-tls/build.gradle // examples/example-tls/pom.xml - netty_tcnative: 'io.netty:netty-tcnative-boringssl-static:2.0.25.Final', + netty_tcnative: 'io.netty:netty-tcnative-boringssl-static:2.0.26.Final', conscrypt: 'org.conscrypt:conscrypt-openjdk-uber:2.2.1', re2j: 'com.google.re2j:re2j:1.2', diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index f169a8e587f..ac24a272c1b 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -24,7 +24,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION -def nettyTcNativeVersion = '2.0.25.Final' +def nettyTcNativeVersion = '2.0.26.Final' def protocVersion = '3.9.0' dependencies { diff --git a/repositories.bzl b/repositories.bzl index f963f85c39d..842d5647302 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -324,108 +324,108 @@ def io_grpc_grpc_proto(): def io_netty_buffer(): jvm_maven_import_external( name = "io_netty_netty_buffer", - artifact = "io.netty:netty-buffer:4.1.38.Final", + artifact = "io.netty:netty-buffer:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "a3dcb49108f83b195e66cdad70b2d4a127c17f1be7f5b228a88ce18908c30b3e", + artifact_sha256 = "7b0171a4e8bcd573e08d9f2bba053c67b557ab5012106a5982ccbae5743814c0", licenses = ["notice"], # Apache 2.0 ) def io_netty_codec(): jvm_maven_import_external( name = "io_netty_netty_codec", - artifact = "io.netty:netty-codec:4.1.38.Final", + artifact = "io.netty:netty-codec:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "8a4cb96e2131eeb8a824014f0ee338b11c6041405446acf73181199ed05744ac", + artifact_sha256 = "e96ced697fb7df589da7c20c995e01f75a9cb246be242bbc4cd3b4af424ff189", licenses = ["notice"], # Apache 2.0 ) def io_netty_codec_http(): jvm_maven_import_external( name = "io_netty_netty_codec_http", - artifact = "io.netty:netty-codec-http:4.1.38.Final", + artifact = "io.netty:netty-codec-http:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "b35c4ac78ed3aaefeb782965ce9f22901e5302bf5e75b75fbed79434ce007e8c", + artifact_sha256 = "eb349c0f1b249af7c7a8fbbd1c761d65d9bc230880cd8d37feab9e8278292625", licenses = ["notice"], # Apache 2.0 ) def io_netty_codec_http2(): jvm_maven_import_external( name = "io_netty_netty_codec_http2", - artifact = "io.netty:netty-codec-http2:4.1.38.Final", + artifact = "io.netty:netty-codec-http2:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "7e2d792407d2da34d3338a3e8f8ed421570fdbf845941b8ee0aa952fe0e07026", + artifact_sha256 = "8bac9625eb68635396eb0c13c9cc0b22bde7c83d0cd2dae3fe9b6f9cf929e372", licenses = ["notice"], # Apache 2.0 ) def io_netty_codec_socks(): jvm_maven_import_external( name = "io_netty_netty_codec_socks", - artifact = "io.netty:netty-codec-socks:4.1.38.Final", + artifact = "io.netty:netty-codec-socks:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "16d932d76d06992923ce640609d297fe35d9f7b219ea5f0514a4259f1f1f2146", + artifact_sha256 = "7f14b3a95ee9aa5a26f66af668690578a81a883683ac1c4ca9e9afdf4d4c7894", licenses = ["notice"], # Apache 2.0 ) def io_netty_common(): jvm_maven_import_external( name = "io_netty_netty_common", - artifact = "io.netty:netty-common:4.1.38.Final", + artifact = "io.netty:netty-common:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "710df7c27fe5ba4b15689ae10668cd10ab3b618a1291f3a47b2cc292a0fa67da", + artifact_sha256 = "3d0a918d78292eeca02a7bb2188daa4e5053b6e29b71e6308309033e121242b5", licenses = ["notice"], # Apache 2.0 ) def io_netty_handler(): jvm_maven_import_external( name = "io_netty_netty_handler", - artifact = "io.netty:netty-handler:4.1.38.Final", + artifact = "io.netty:netty-handler:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "b49b57dbdc88a2c77e3ea9b9d00d3136f28771e059b74a7be7458d7a86bfccd1", + artifact_sha256 = "11eda86500c33b9d386719b5419f513fd9c097d13894f25dd0c75b610d636e03", licenses = ["notice"], # Apache 2.0 ) def io_netty_handler_proxy(): jvm_maven_import_external( name = "io_netty_netty_handler_proxy", - artifact = "io.netty:netty-handler-proxy:4.1.38.Final", + artifact = "io.netty:netty-handler-proxy:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "9dab309a0422dd9858f431d503b58b854b37d2545c50ad7b4771f34d2288e5c0", + artifact_sha256 = "25f22da21c29ab0d3b6b889412351bcfc5f9ccd42e07d2d5513d5c4eb571f343", licenses = ["notice"], # Apache 2.0 ) def io_netty_resolver(): jvm_maven_import_external( name = "io_netty_netty_resolver", - artifact = "io.netty:netty-resolver:4.1.38.Final", + artifact = "io.netty:netty-resolver:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "3692c12a0035e566d5cd1dc1529d4f61725304c5e88817ae78b5c2f7f6d86cad", + artifact_sha256 = "89768242b6b7cce9bd9f5945ad21d1b4bae515c6b1bf03a8af5d1899779cebc9", licenses = ["notice"], # Apache 2.0 ) def io_netty_tcnative_boringssl_static(): jvm_maven_import_external( name = "io_netty_netty_tcnative_boringssl_static", - artifact = "io.netty:netty-tcnative-boringssl-static:2.0.25.Final", + artifact = "io.netty:netty-tcnative-boringssl-static:2.0.26.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "96d9c14ab4c47cbad7fec9bdb083917db971d3754d6c7fa89f958bc719e230ed", + artifact_sha256 = "5f074a4b112bf7d087331e33d2da720745c5bda047b34b64bd70aaaae4de24c6", licenses = ["notice"], # Apache 2.0 ) def io_netty_transport(): jvm_maven_import_external( name = "io_netty_netty_transport", - artifact = "io.netty:netty-transport:4.1.38.Final", + artifact = "io.netty:netty-transport:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "5f826976585a49aae9b495290125a60a59dc6887fbe4c70da3182a83fb8bfa88", + artifact_sha256 = "dfa817a156ea263aa9ad8364a2e226527665c9722aca40a7945f228c2c14f1da", licenses = ["notice"], # Apache 2.0 ) def io_netty_transport_native_epoll(): jvm_maven_import_external( name = "io_netty_netty_transport_native_epoll", - artifact = "io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.38.Final", + artifact = "io.netty:netty-transport-native-epoll:jar:linux-x86_64:4.1.42.Final", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "7933467e1cfc37bc6fb3f22af471ed69cb66bebaceab73d2041772bb6a38218a", + artifact_sha256 = "7bdf3003d5b60b061b494e62d1bafc420caf800efb743b14ec01ceaef1d3fa3e", licenses = ["notice"], # Apache 2.0 ) From e448f9c7d3148c5bd58243e141570c36e4169795 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Tue, 1 Oct 2019 14:48:28 -0700 Subject: [PATCH 055/131] xds: reimplement bootstrapping with new bootstrap file format design (#6201) This change reimplements Bootstrapper with new design of bootstrap file format, with no longer using ApiConfigSource proto. The new JSON format of the bootstrap file contains a top level "node" and a "xds_server" object, which contains a "server_uri" string and a `channel_creds` list for channel credentials. Unknown fields in the bootstrap file are allowed by ignored so that the implementation does not break when new fields are added in the future. Therefore, we cannot simply create a custom proto file and use proto util to parse it. --- xds/build.gradle | 11 +- .../main/java/io/grpc/xds/Bootstrapper.java | 216 ++++++++++++++--- xds/src/main/proto/bootstrap.proto | 39 --- .../java/io/grpc/xds/BootstrapperTest.java | 226 ++++++++++-------- 4 files changed, 306 insertions(+), 186 deletions(-) delete mode 100644 xds/src/main/proto/bootstrap.proto diff --git a/xds/build.gradle b/xds/build.gradle index 67902d17d53..a8dc96da270 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -20,9 +20,8 @@ dependencies { compile project(':grpc-protobuf'), project(':grpc-stub'), project(':grpc-core'), - project(':grpc-netty'), - project(':grpc-services'), - project(':grpc-auth') + project(':grpc-services') + compile (libraries.pgv) { // PGV depends on com.google.protobuf:protobuf-java 3.6.1 conflicting with :grpc-protobuf exclude group: 'com.google.protobuf' @@ -31,12 +30,6 @@ dependencies { // prefer 26.0-android from libraries instead of 20.0 exclude group: 'com.google.guava', module: 'guava' } - compile (libraries.google_auth_oauth2_http) { - // prefer 26.0-android from libraries instead of 25.1-android - exclude group: 'com.google.guava', module: 'guava' - // prefer 0.19.2 from libraries instead of 0.18.0 - exclude group: 'io.opencensus', module: 'opencensus-api' - } testCompile project(':grpc-core').sourceSets.test.output diff --git a/xds/src/main/java/io/grpc/xds/Bootstrapper.java b/xds/src/main/java/io/grpc/xds/Bootstrapper.java index e4416b386fd..841b2ecb87b 100644 --- a/xds/src/main/java/io/grpc/xds/Bootstrapper.java +++ b/xds/src/main/java/io/grpc/xds/Bootstrapper.java @@ -16,19 +16,24 @@ package io.grpc.xds; -import com.google.auth.oauth2.ComputeEngineCredentials; import com.google.common.annotations.VisibleForTesting; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.util.JsonFormat; -import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; -import io.envoyproxy.envoy.api.v2.core.ApiConfigSource.ApiType; +import com.google.protobuf.ListValue; +import com.google.protobuf.NullValue; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import io.envoyproxy.envoy.api.v2.core.Locality; import io.envoyproxy.envoy.api.v2.core.Node; -import io.grpc.CallCredentials; -import io.grpc.auth.MoreCallCredentials; +import io.grpc.internal.JsonParser; +import io.grpc.internal.JsonUtil; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** @@ -47,9 +52,9 @@ static Bootstrapper getInstance() throws Exception { } /** - * Returns the canonical name of the traffic director to be connected to. + * Returns the URI the traffic director to be connected to. */ - abstract String getBalancerName(); + abstract String getServerUri(); /** * Returns a {@link Node} message with project/network metadata in it to be included in @@ -60,7 +65,7 @@ static Bootstrapper getInstance() throws Exception { /** * Returns the credentials to use when communicating with the xDS server. */ - abstract CallCredentials getCallCredentials(); + abstract List getChannelCredentials(); @VisibleForTesting static final class FileBasedBootstrapper extends Bootstrapper { @@ -68,10 +73,9 @@ static final class FileBasedBootstrapper extends Bootstrapper { private static final Exception failToBootstrapException; private static final Bootstrapper defaultInstance; - private final String balancerName; + private final String serverUri; private final Node node; - // TODO(chengyuanzhang): Add configuration for call credentials loaded from bootstrap file. - // hard-coded for alpha release. + private final List channelCredsList; static { Bootstrapper instance = null; @@ -86,23 +90,15 @@ static final class FileBasedBootstrapper extends Bootstrapper { } @VisibleForTesting - FileBasedBootstrapper(Bootstrap bootstrapConfig) throws IOException { - ApiConfigSource serverConfig = bootstrapConfig.getXdsServer(); - if (!serverConfig.getApiType().equals(ApiType.GRPC)) { - throw new IOException("Unexpected api type: " + serverConfig.getApiType().toString()); - } - if (serverConfig.getGrpcServicesCount() != 1) { - throw new IOException( - "Unexpected number of gRPC services: expected: 1, actual: " - + serverConfig.getGrpcServicesCount()); - } - balancerName = serverConfig.getGrpcServices(0).getGoogleGrpc().getTargetUri(); - node = bootstrapConfig.getNode(); + FileBasedBootstrapper(BootstrapInfo bootstrapInfo) { + this.serverUri = bootstrapInfo.serverConfig.uri; + this.node = bootstrapInfo.node; + this.channelCredsList = bootstrapInfo.serverConfig.channelCredsList; } @Override - String getBalancerName() { - return balancerName; + String getServerUri() { + return serverUri; } @Override @@ -111,12 +107,12 @@ Node getNode() { } @Override - CallCredentials getCallCredentials() { - return MoreCallCredentials.from(ComputeEngineCredentials.create()); + List getChannelCredentials() { + return Collections.unmodifiableList(channelCredsList); } } - private static Bootstrap readConfig() throws IOException { + private static BootstrapInfo readConfig() throws IOException { String filePath = System.getenv(BOOTSTRAP_PATH_SYS_ENV_VAR); if (filePath == null) { throw new IOException("Environment variable " + BOOTSTRAP_PATH_SYS_ENV_VAR + " not found."); @@ -125,9 +121,161 @@ private static Bootstrap readConfig() throws IOException { } @VisibleForTesting - static Bootstrap parseConfig(String rawData) throws InvalidProtocolBufferException { - Bootstrap.Builder bootstrapBuilder = Bootstrap.newBuilder(); - JsonFormat.parser().merge(rawData, bootstrapBuilder); - return bootstrapBuilder.build(); + static BootstrapInfo parseConfig(String rawData) throws IOException { + @SuppressWarnings("unchecked") + Map rawBootstrap = (Map) JsonParser.parse(rawData); + + Map rawServerConfig = JsonUtil.getObject(rawBootstrap, "xds_server"); + if (rawServerConfig == null) { + throw new IOException("Invalid bootstrap: 'xds_server' does not exist."); + } + // Field "server_uri" is required. + String serverUri = JsonUtil.getString(rawServerConfig, "server_uri"); + if (serverUri == null) { + throw new IOException("Invalid bootstrap: 'xds_server : server_uri' does not exist."); + } + List channelCredsOptions = new ArrayList<>(); + List rawChannelCredsList = JsonUtil.getList(rawServerConfig, "channel_creds"); + // List of channel creds is optional. + if (rawChannelCredsList != null) { + List> channelCredsList = JsonUtil.checkObjectList(rawChannelCredsList); + for (Map channelCreds : channelCredsList) { + String type = JsonUtil.getString(channelCreds, "type"); + if (type == null) { + throw new IOException("Invalid bootstrap: 'channel_creds' contains unknown type."); + } + ChannelCreds creds = new ChannelCreds(type, JsonUtil.getObject(channelCreds, "config")); + channelCredsOptions.add(creds); + } + } + ServerConfig serverConfig = new ServerConfig(serverUri, channelCredsOptions); + + Map rawNode = JsonUtil.getObject(rawBootstrap, "node"); + if (rawNode == null) { + throw new IOException("Invalid bootstrap: 'node' does not exist."); + } + // Fields in "node" are not checked. + Node.Builder nodeBuilder = Node.newBuilder(); + String id = JsonUtil.getString(rawNode, "id"); + if (id != null) { + nodeBuilder.setId(id); + } + String cluster = JsonUtil.getString(rawNode, "cluster"); + if (cluster != null) { + nodeBuilder.setCluster(cluster); + } + Map metadata = JsonUtil.getObject(rawNode, "metadata"); + if (metadata != null) { + Struct.Builder structBuilder = Struct.newBuilder(); + for (Map.Entry entry : metadata.entrySet()) { + structBuilder.putFields(entry.getKey(), convertToValue(entry.getValue())); + } + nodeBuilder.setMetadata(structBuilder); + } + Map rawLocality = JsonUtil.getObject(rawNode, "locality"); + if (rawLocality != null) { + Locality.Builder localityBuilder = Locality.newBuilder(); + String region = JsonUtil.getString(rawLocality, "region"); + if (region == null) { + throw new IOException("Invalid bootstrap: malformed 'node : locality'."); + } + localityBuilder.setRegion(region); + if (rawLocality.containsKey("zone")) { + localityBuilder.setZone(JsonUtil.getString(rawLocality, "zone")); + } + if (rawLocality.containsKey("sub_zone")) { + localityBuilder.setSubZone(JsonUtil.getString(rawLocality, "sub_zone")); + } + nodeBuilder.setLocality(localityBuilder); + } + String buildVersion = JsonUtil.getString(rawNode, "build_version"); + if (buildVersion != null) { + nodeBuilder.setBuildVersion(buildVersion); + } + + return new BootstrapInfo(serverConfig, nodeBuilder.build()); + } + + /** + * Converts Java representation of the given JSON value to protobuf's {@link + * com.google.protobuf.Value} representation. + * + *

The given {@code rawObject} must be a valid JSON value in Java representation, which is + * either a {@code Map}, {@code List}, {@code String}, {@code Double}, + * {@code Boolean}, or {@code null}. + */ + private static Value convertToValue(Object rawObject) { + Value.Builder valueBuilder = Value.newBuilder(); + if (rawObject == null) { + valueBuilder.setNullValue(NullValue.NULL_VALUE); + } else if (rawObject instanceof Double) { + valueBuilder.setNumberValue((Double) rawObject); + } else if (rawObject instanceof String) { + valueBuilder.setStringValue((String) rawObject); + } else if (rawObject instanceof Boolean) { + valueBuilder.setBoolValue((Boolean) rawObject); + } else if (rawObject instanceof Map) { + Struct.Builder structBuilder = Struct.newBuilder(); + @SuppressWarnings("unchecked") + Map map = (Map) rawObject; + for (Map.Entry entry : map.entrySet()) { + structBuilder.putFields(entry.getKey(), convertToValue(entry.getValue())); + } + valueBuilder.setStructValue(structBuilder); + } else if (rawObject instanceof List) { + ListValue.Builder listBuilder = ListValue.newBuilder(); + List list = (List) rawObject; + for (Object obj : list) { + listBuilder.addValues(convertToValue(obj)); + } + valueBuilder.setListValue(listBuilder); + } + return valueBuilder.build(); + } + + // TODO(chengyuanzhang): May need more complex structure for channel creds config representation. + static class ChannelCreds { + private final String type; + @Nullable + private final Map config; + + @VisibleForTesting + ChannelCreds(String type, @Nullable Map config) { + this.type = type; + this.config = config; + } + + String getType() { + return type; + } + + @Nullable + Map getConfig() { + return config; + } + } + + @VisibleForTesting + static class BootstrapInfo { + final ServerConfig serverConfig; + final Node node; + + @VisibleForTesting + BootstrapInfo(ServerConfig serverConfig, Node node) { + this.serverConfig = serverConfig; + this.node = node; + } + } + + @VisibleForTesting + static class ServerConfig { + final String uri; + final List channelCredsList; + + @VisibleForTesting + ServerConfig(String uri, List channelCredsList) { + this.uri = uri; + this.channelCredsList = channelCredsList; + } } } diff --git a/xds/src/main/proto/bootstrap.proto b/xds/src/main/proto/bootstrap.proto deleted file mode 100644 index 6a45a56125f..00000000000 --- a/xds/src/main/proto/bootstrap.proto +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019 The gRPC Authors -// All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// An integration test service that covers all the method signature permutations -// of unary/streaming requests/responses. - -syntax = "proto3"; - -package io.grpc.xds; - -option java_outer_classname = "BootstrapProto"; -option java_multiple_files = true; -option java_package = "io.grpc.xds"; - -import "envoy/api/v2/core/base.proto"; -import "envoy/api/v2/core/config_source.proto"; - -// Configurations containing the information needed for xDS load balancer to bootstrap its -// communication with the xDS server. -// This proto message is defined for the convenience of parsing JSON bootstrap file in xDS load -// balancing policy only. It should not be used for any other purposes. -message Bootstrap { - // Metadata to be added to the Node message in xDS requests. - envoy.api.v2.core.Node node = 1 [json_name = "node"]; - - // Configurations including the name of the xDS server to contact, the credentials to use, etc. - envoy.api.v2.core.ApiConfigSource xds_server = 2 [json_name = "xds_server"]; -} diff --git a/xds/src/test/java/io/grpc/xds/BootstrapperTest.java b/xds/src/test/java/io/grpc/xds/BootstrapperTest.java index 07158c9dee1..58f9ccea01a 100644 --- a/xds/src/test/java/io/grpc/xds/BootstrapperTest.java +++ b/xds/src/test/java/io/grpc/xds/BootstrapperTest.java @@ -18,17 +18,17 @@ import static com.google.common.truth.Truth.assertThat; -import com.google.protobuf.InvalidProtocolBufferException; +import com.google.common.collect.ImmutableList; import com.google.protobuf.Struct; import com.google.protobuf.Value; -import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; -import io.envoyproxy.envoy.api.v2.core.ApiConfigSource.ApiType; -import io.envoyproxy.envoy.api.v2.core.GrpcService; -import io.envoyproxy.envoy.api.v2.core.GrpcService.GoogleGrpc; import io.envoyproxy.envoy.api.v2.core.Locality; import io.envoyproxy.envoy.api.v2.core.Node; +import io.grpc.xds.Bootstrapper.BootstrapInfo; +import io.grpc.xds.Bootstrapper.ChannelCreds; import io.grpc.xds.Bootstrapper.FileBasedBootstrapper; +import io.grpc.xds.Bootstrapper.ServerConfig; import java.io.IOException; +import java.util.List; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -42,162 +42,180 @@ public class BootstrapperTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Test - public void validBootstrap() throws IOException { - Bootstrap config = - Bootstrap.newBuilder() - .setNode( - Node.newBuilder() - .setId("ENVOY_NODE_ID") - .setLocality( - Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) - .setMetadata( - Struct.newBuilder() - .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", - Value.newBuilder().setStringValue("ENVOY_PORT").build()) - .putFields("TRAFFICDIRECTOR_NETWORK_NAME", - Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()))) - .setXdsServer(ApiConfigSource.newBuilder() - .setApiType(ApiType.GRPC) - .addGrpcServices( - GrpcService.newBuilder() - .setGoogleGrpc( - GoogleGrpc.newBuilder() - .setTargetUri("trafficdirector.googleapis.com:443").build()))) + public void validBootstrap() { + List channelCredsList = + ImmutableList.of(new ChannelCreds("TLS", null), new ChannelCreds("LOAS", null)); + ServerConfig serverConfig = + new ServerConfig("trafficdirector.googleapis.com:443", channelCredsList); + + Node node = + Node.newBuilder() + .setId("ENVOY_NODE_ID") + .setCluster("ENVOY_CLUSTER") + .setLocality( + Locality.newBuilder() + .setRegion("ENVOY_REGION").setZone("ENVOY_ZONE").setSubZone("ENVOY_SUBZONE")) + .setMetadata( + Struct.newBuilder() + .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", + Value.newBuilder().setStringValue("ENVOY_PORT").build()) + .putFields("TRAFFICDIRECTOR_NETWORK_NAME", + Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build())) .build(); + BootstrapInfo config = new BootstrapInfo(serverConfig, node); Bootstrapper bootstrapper = new FileBasedBootstrapper(config); - assertThat(bootstrapper.getBalancerName()).isEqualTo("trafficdirector.googleapis.com:443"); + assertThat(bootstrapper.getServerUri()).isEqualTo("trafficdirector.googleapis.com:443"); assertThat(bootstrapper.getNode()) .isEqualTo( Node.newBuilder() .setId("ENVOY_NODE_ID") - .setLocality(Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) + .setCluster("ENVOY_CLUSTER") + .setLocality( + Locality.newBuilder() + .setRegion("ENVOY_REGION") + .setZone("ENVOY_ZONE") + .setSubZone("ENVOY_SUBZONE")) .setMetadata( Struct.newBuilder() .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", Value.newBuilder().setStringValue("ENVOY_PORT").build()) .putFields("TRAFFICDIRECTOR_NETWORK_NAME", Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()) - .build()).build()); + .build()) + .build()); + assertThat(bootstrapper.getChannelCredentials()).hasSize(2); + assertThat(bootstrapper.getChannelCredentials().get(0).getType()).isEqualTo("TLS"); + assertThat(bootstrapper.getChannelCredentials().get(0).getConfig()).isNull(); + assertThat(bootstrapper.getChannelCredentials().get(1).getType()).isEqualTo("LOAS"); + assertThat(bootstrapper.getChannelCredentials().get(1).getConfig()).isNull(); } @Test - public void unsupportedApiType() throws IOException { - Bootstrap config = - Bootstrap.newBuilder() - .setNode( - Node.newBuilder() - .setId("ENVOY_NODE_ID") - .setLocality( - Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) - .setMetadata( - Struct.newBuilder() - .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", - Value.newBuilder().setStringValue("ENVOY_PORT").build()) - .putFields("TRAFFICDIRECTOR_NETWORK_NAME", - Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()))) - .setXdsServer(ApiConfigSource.newBuilder() - .setApiType(ApiType.REST) - .addGrpcServices( - GrpcService.newBuilder() - .setGoogleGrpc( - GoogleGrpc.newBuilder() - .setTargetUri("trafficdirector.googleapis.com:443").build()))) - .build(); + public void parseBootstrap_validData() throws IOException { + String rawData = "{" + + "\"node\": {" + + "\"id\": \"ENVOY_NODE_ID\"," + + "\"cluster\": \"ENVOY_CLUSTER\"," + + "\"locality\": {" + + "\"region\": \"ENVOY_REGION\", \"zone\": \"ENVOY_ZONE\", \"sub_zone\": \"ENVOY_SUBZONE\"" + + "}," + + "\"metadata\": {" + + "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", " + + "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"" + + "}" + + "}," + + "\"xds_server\": {" + + "\"server_uri\": \"trafficdirector.googleapis.com:443\"," + + "\"channel_creds\": " + + "[ {\"type\": \"TLS\"}, {\"type\": \"LOAS\"} ]" + + "} " + + "}"; - thrown.expect(IOException.class); - thrown.expectMessage("Unexpected api type: REST"); - new FileBasedBootstrapper(config); + BootstrapInfo info = Bootstrapper.parseConfig(rawData); + assertThat(info.serverConfig.uri).isEqualTo("trafficdirector.googleapis.com:443"); + assertThat(info.serverConfig.channelCredsList).hasSize(2); + assertThat(info.serverConfig.channelCredsList.get(0).getType()).isEqualTo("TLS"); + assertThat(info.serverConfig.channelCredsList.get(0).getConfig()).isNull(); + assertThat(info.serverConfig.channelCredsList.get(1).getType()).isEqualTo("LOAS"); + assertThat(info.serverConfig.channelCredsList.get(1).getConfig()).isNull(); + assertThat(info.node).isEqualTo( + Node.newBuilder() + .setId("ENVOY_NODE_ID") + .setCluster("ENVOY_CLUSTER") + .setLocality( + Locality.newBuilder() + .setRegion("ENVOY_REGION").setZone("ENVOY_ZONE").setSubZone("ENVOY_SUBZONE")) + .setMetadata( + Struct.newBuilder() + .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", + Value.newBuilder().setStringValue("ENVOY_PORT").build()) + .putFields("TRAFFICDIRECTOR_NETWORK_NAME", + Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()) + .build()) + .build()); } @Test - public void tooManyGrpcServices() throws IOException { - Bootstrap config = - Bootstrap.newBuilder() - .setNode( - Node.newBuilder() - .setId("ENVOY_NODE_ID") - .setLocality( - Locality.newBuilder().setZone("ENVOY_ZONE").setRegion("ENVOY_REGION")) - .setMetadata( - Struct.newBuilder() - .putFields("TRAFFICDIRECTOR_INTERCEPTION_PORT", - Value.newBuilder().setStringValue("ENVOY_PORT").build()) - .putFields("TRAFFICDIRECTOR_NETWORK_NAME", - Value.newBuilder().setStringValue("VPC_NETWORK_NAME").build()))) - .setXdsServer(ApiConfigSource.newBuilder() - .setApiType(ApiType.GRPC) - .addGrpcServices( - GrpcService.newBuilder() - .setGoogleGrpc( - GoogleGrpc.newBuilder() - .setTargetUri("trafficdirector.googleapis.com:443").build())) - .addGrpcServices( - GrpcService.newBuilder() - .setGoogleGrpc( - GoogleGrpc.newBuilder() - .setTargetUri("foobar.googleapis.com:443").build())) - ) - .build(); + public void parseBootstrap_emptyData() throws IOException { + String rawData = ""; thrown.expect(IOException.class); - thrown.expectMessage("Unexpected number of gRPC services: expected: 1, actual: 2"); - new FileBasedBootstrapper(config); + Bootstrapper.parseConfig(rawData); } @Test - public void parseBootstrap_emptyData() throws InvalidProtocolBufferException { - String rawData = ""; + public void parseBootstrap_minimumRequiredFields() throws IOException { + String rawData = "{" + + "\"node\": {}," + + "\"xds_server\": {" + + "\"server_uri\": \"trafficdirector.googleapis.com:443\"" + + "}" + + "}"; + + BootstrapInfo info = Bootstrapper.parseConfig(rawData); + assertThat(info.serverConfig.uri).isEqualTo("trafficdirector.googleapis.com:443"); + assertThat(info.node).isEqualTo(Node.getDefaultInstance()); + } + + @Test + public void parseBootstrap_noNode() throws IOException { + String rawData = "{" + + "\"xds_server\": {" + + "\"server_uri\": \"trafficdirector.googleapis.com:443\"," + + "\"channel_creds\": " + + "[ {\"type\": \"TLS\"}, {\"type\": \"LOAS\"} ]" + + "} " + + "}"; - thrown.expect(InvalidProtocolBufferException.class); + thrown.expect(IOException.class); + thrown.expectMessage("Invalid bootstrap: 'node' does not exist."); Bootstrapper.parseConfig(rawData); } @Test - public void parseBootstrap_invalidNodeProto() throws InvalidProtocolBufferException { + public void parseBootstrap_noXdsServer() throws IOException { String rawData = "{" + "\"node\": {" + "\"id\": \"ENVOY_NODE_ID\"," - + "\"bad_field\": \"bad_value\"" + + "\"cluster\": \"ENVOY_CLUSTER\"," + "\"locality\": {" - + "\"zone\": \"ENVOY_ZONE\"}," + + "\"region\": \"ENVOY_REGION\", \"zone\": \"ENVOY_ZONE\", \"sub_zone\": \"ENVOY_SUBZONE\"" + + "}," + "\"metadata\": {" + "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", " + "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"" + "}" - + "}," - + "\"xds_server\": {" - + "\"api_type\": \"GRPC\"," - + "\"grpc_services\": " - + "[ {\"google_grpc\": {\"target_uri\": \"trafficdirector.googleapis.com:443\"} } ]" - + "} " + + "}" + "}"; - thrown.expect(InvalidProtocolBufferException.class); + thrown.expect(IOException.class); + thrown.expectMessage("Invalid bootstrap: 'xds_server' does not exist."); Bootstrapper.parseConfig(rawData); } @Test - public void parseBootstrap_invalidApiConfigSourceProto() throws InvalidProtocolBufferException { + public void parseBootstrap_noServerUri() throws IOException { String rawData = "{" + "\"node\": {" + "\"id\": \"ENVOY_NODE_ID\"," + + "\"cluster\": \"ENVOY_CLUSTER\"," + "\"locality\": {" - + "\"zone\": \"ENVOY_ZONE\"}," + + "\"region\": \"ENVOY_REGION\", \"zone\": \"ENVOY_ZONE\", \"sub_zone\": \"ENVOY_SUBZONE\"" + + "}," + "\"metadata\": {" + "\"TRAFFICDIRECTOR_INTERCEPTION_PORT\": \"ENVOY_PORT\", " + "\"TRAFFICDIRECTOR_NETWORK_NAME\": \"VPC_NETWORK_NAME\"" + "}" + "}," + "\"xds_server\": {" - + "\"api_type\": \"GRPC\"," - + "\"bad_field\": \"bad_value\"" - + "\"grpc_services\": " - + "[ {\"google_grpc\": {\"target_uri\": \"trafficdirector.googleapis.com:443\"} } ]" + + "\"channel_creds\": " + + "[ {\"type\": \"TLS\"}, {\"type\": \"LOAS\"} ]" + "} " + "}"; - thrown.expect(InvalidProtocolBufferException.class); + thrown.expect(IOException.class); + thrown.expectMessage("Invalid bootstrap: 'xds_server : server_uri' does not exist."); Bootstrapper.parseConfig(rawData); } } From 2bc8c452f311a408be116e2c399f44db2f52cd72 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Tue, 1 Oct 2019 16:33:26 -0700 Subject: [PATCH 056/131] xds: restructure XdsLoadBalancer Part 4: LookasideChannelLb Note: XdsComms2 is a temporary refactor of XdsComms, and will be re-implemented with the new XdsClient design. --- .../java/io/grpc/xds/LookasideChannelLb.java | 222 +++++++++ xds/src/main/java/io/grpc/xds/XdsComms2.java | 247 ++++++++++ .../io/grpc/xds/LookasideChannelLbTest.java | 433 ++++++++++++++++++ 3 files changed, 902 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/LookasideChannelLb.java create mode 100644 xds/src/main/java/io/grpc/xds/XdsComms2.java create mode 100644 xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java diff --git a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java new file mode 100644 index 00000000000..d0b7fb0c7e3 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java @@ -0,0 +1,222 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.logging.Level.FINEST; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; +import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload; +import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; +import io.envoyproxy.envoy.type.FractionalPercent; +import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; +import io.grpc.LoadBalancer; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Status; +import io.grpc.internal.ExponentialBackoffPolicy; +import io.grpc.internal.GrpcUtil; +import io.grpc.xds.LoadReportClient.LoadReportCallback; +import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.XdsComms.LbEndpoint; +import io.grpc.xds.XdsComms.LocalityInfo; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Logger; + +/** + * A load balancer that has a lookaside channel. This layer of load balancer creates a channel to + * the remote load balancer. LrsClient, LocalityStore and XdsComms are three branches below this + * layer, and their implementations are provided by their factories. + */ +final class LookasideChannelLb extends LoadBalancer { + + private final ManagedChannel lbChannel; + private final LoadReportClient lrsClient; + private final XdsComms2 xdsComms2; + + @VisibleForTesting + LookasideChannelLb( + Helper helper, + AdsStreamCallback adsCallback, + String balancerName, + LoadReportClient lrsClient, + final LocalityStore localityStore) { + lbChannel = initLbChannel(helper, balancerName); + LoadReportCallback lrsCallback = + new LoadReportCallback() { + @Override + public void onReportResponse(long reportIntervalNano) { + localityStore.updateOobMetricsReportInterval(reportIntervalNano); + } + }; + this.lrsClient = lrsClient; + + AdsStreamCallback2 adsCallback2 = new AdsStreamCallback2Impl( + adsCallback, lrsClient, lrsCallback, localityStore) ; + xdsComms2 = new XdsComms2( + lbChannel, helper, adsCallback2, new ExponentialBackoffPolicy.Provider(), + GrpcUtil.STOPWATCH_SUPPLIER); + } + + private static int rateInMillion(FractionalPercent fractionalPercent) { + int numerator = fractionalPercent.getNumerator(); + checkArgument(numerator >= 0, "numerator shouldn't be negative in %s", fractionalPercent); + + DenominatorType type = fractionalPercent.getDenominator(); + switch (type) { + case TEN_THOUSAND: + numerator *= 100; + break; + case HUNDRED: + numerator *= 100_00; + break; + case MILLION: + break; + default: + throw new IllegalArgumentException("unknown denominator type of " + fractionalPercent); + } + + if (numerator > 1000_000) { + numerator = 1000_000; + } + + return numerator; + } + + private static ManagedChannel initLbChannel(Helper helper, String balancerName) { + ManagedChannel channel; + try { + channel = helper.createResolvingOobChannel(balancerName); + } catch (UnsupportedOperationException uoe) { + // Temporary solution until createResolvingOobChannel is implemented + // FIXME (https://github.com/grpc/grpc-java/issues/5495) + Logger logger = Logger.getLogger(LookasideChannelLb.class.getName()); + if (logger.isLoggable(FINEST)) { + logger.log( + FINEST, + "createResolvingOobChannel() not supported by the helper: " + helper, + uoe); + logger.log( + FINEST, + "creating oob channel for target {0} using default ManagedChannelBuilder", + balancerName); + } + channel = ManagedChannelBuilder.forTarget(balancerName).build(); + } + return channel; + } + + @Override + public void handleNameResolutionError(Status error) { + // NO-OP? + } + + @Override + public void shutdown() { + lrsClient.stopLoadReporting(); + xdsComms2.shutdownLbRpc(); + lbChannel.shutdown(); + } + + // TODO(zdapeng): The old AdsStreamCallback will be renamed to LookasideChannelCallback, + // and AdsStreamCallback2 will be renamed to AdsStreamCallback + /** + * Callback on ADS stream events. The callback methods should be called in a proper {@link + * io.grpc.SynchronizationContext}. + */ + interface AdsStreamCallback2 { + void onEdsResponse(ClusterLoadAssignment clusterLoadAssignment); + + void onError(); + } + + private static final class AdsStreamCallback2Impl implements AdsStreamCallback2 { + + final AdsStreamCallback adsCallback; + final LoadReportClient lrsClient; + final LoadReportCallback lrsCallback; + final LocalityStore localityStore; + boolean firstEdsResponseReceived; + + AdsStreamCallback2Impl( + AdsStreamCallback adsCallback, LoadReportClient lrsClient, LoadReportCallback lrsCallback, + LocalityStore localityStore) { + this.adsCallback = adsCallback; + this.lrsClient = lrsClient; + this.lrsCallback = lrsCallback; + this.localityStore = localityStore; + } + + @Override + public void onEdsResponse(ClusterLoadAssignment clusterLoadAssignment) { + if (!firstEdsResponseReceived) { + firstEdsResponseReceived = true; + adsCallback.onWorking(); + lrsClient.startLoadReporting(lrsCallback); + } + + List dropOverloadsProto = + clusterLoadAssignment.getPolicy().getDropOverloadsList(); + ImmutableList.Builder dropOverloadsBuilder + = ImmutableList.builder(); + for (ClusterLoadAssignment.Policy.DropOverload dropOverload + : dropOverloadsProto) { + int rateInMillion = rateInMillion(dropOverload.getDropPercentage()); + dropOverloadsBuilder.add(new XdsComms.DropOverload( + dropOverload.getCategory(), rateInMillion)); + if (rateInMillion == 1000_000) { + adsCallback.onAllDrop(); + break; + } + } + ImmutableList dropOverloads = dropOverloadsBuilder.build(); + localityStore.updateDropPercentage(dropOverloads); + + List localities = clusterLoadAssignment.getEndpointsList(); + ImmutableMap.Builder localityEndpointsMapping = + new ImmutableMap.Builder<>(); + for (LocalityLbEndpoints localityLbEndpoints : localities) { + io.envoyproxy.envoy.api.v2.core.Locality localityProto = + localityLbEndpoints.getLocality(); + XdsLocality locality = XdsLocality.fromLocalityProto(localityProto); + List lbEndPoints = new ArrayList<>(); + for (io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint lbEndpoint + : localityLbEndpoints.getLbEndpointsList()) { + lbEndPoints.add(new LbEndpoint(lbEndpoint)); + } + int localityWeight = localityLbEndpoints.getLoadBalancingWeight().getValue(); + int priority = localityLbEndpoints.getPriority(); + + if (localityWeight != 0) { + localityEndpointsMapping.put( + locality, new LocalityInfo(lbEndPoints, localityWeight, priority)); + } + } + + localityStore.updateLocalityStore(localityEndpointsMapping.build()); + } + + @Override + public void onError() { + adsCallback.onError(); + } + } +} diff --git a/xds/src/main/java/io/grpc/xds/XdsComms2.java b/xds/src/main/java/io/grpc/xds/XdsComms2.java new file mode 100644 index 00000000000..cbe5512e10c --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/XdsComms2.java @@ -0,0 +1,247 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; + +import com.google.common.base.Stopwatch; +import com.google.common.base.Supplier; +import com.google.protobuf.InvalidProtocolBufferException; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; +import io.envoyproxy.envoy.api.v2.DiscoveryRequest; +import io.envoyproxy.envoy.api.v2.DiscoveryResponse; +import io.envoyproxy.envoy.api.v2.core.Node; +import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc; +import io.grpc.ChannelLogger.ChannelLogLevel; +import io.grpc.LoadBalancer.Helper; +import io.grpc.ManagedChannel; +import io.grpc.Status; +import io.grpc.SynchronizationContext.ScheduledHandle; +import io.grpc.internal.BackoffPolicy; +import io.grpc.stub.StreamObserver; +import io.grpc.xds.LookasideChannelLb.AdsStreamCallback2; +import java.util.concurrent.TimeUnit; +import javax.annotation.CheckForNull; + +/** + * ADS client implementation. + */ +// TODO(zdapeng): This is a temporary and easy refactor of XdsComms, will be replaced by XdsClient. +// Tests are deferred in XdsClientTest, otherwise it's just a refactor of XdsCommsTest. +final class XdsComms2 { + private final ManagedChannel channel; + private final Helper helper; + private final BackoffPolicy.Provider backoffPolicyProvider; + private final Supplier stopwatchSupplier; + + @CheckForNull + private ScheduledHandle adsRpcRetryTimer; + + // never null + private BackoffPolicy adsRpcRetryPolicy; + // never null + private AdsStream adsStream; + + private final class AdsStream { + static final String EDS_TYPE_URL = + "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment"; + + final AdsStreamCallback2 adsStreamCallback2; + final StreamObserver xdsRequestWriter; + final Stopwatch retryStopwatch = stopwatchSupplier.get().start(); + + final StreamObserver xdsResponseReader = + new StreamObserver() { + // Must be accessed in SynchronizationContext + boolean firstEdsResponseReceived; + + @Override + public void onNext(final DiscoveryResponse value) { + + class HandleResponseRunnable implements Runnable { + + @Override + public void run() { + String typeUrl = value.getTypeUrl(); + if (EDS_TYPE_URL.equals(typeUrl)) { + // Assuming standard mode. + + ClusterLoadAssignment clusterLoadAssignment; + try { + // maybe better to run this deserialization task out of syncContext? + clusterLoadAssignment = + value.getResources(0).unpack(ClusterLoadAssignment.class); + } catch (InvalidProtocolBufferException | RuntimeException e) { + cancelRpc("Received invalid EDS response", e); + adsStreamCallback2.onError(); + scheduleRetry(); + return; + } + + helper.getChannelLogger().log( + ChannelLogLevel.DEBUG, + "Received an EDS response: {0}", clusterLoadAssignment); + adsStreamCallback2.onEdsResponse(clusterLoadAssignment); + } + } + } + + helper.getSynchronizationContext().execute(new HandleResponseRunnable()); + } + + @Override + public void onError(Throwable t) { + helper.getSynchronizationContext().execute( + new Runnable() { + @Override + public void run() { + closed = true; + if (cancelled) { + return; + } + adsStreamCallback2.onError(); + scheduleRetry(); + } + }); + } + + @Override + public void onCompleted() { + onError(Status.INTERNAL.withDescription("Server closed the ADS streaming RPC") + .asException()); + } + + // run in SynchronizationContext + void scheduleRetry() { + if (channel.isShutdown()) { + return; + } + + checkState( + cancelled || closed, + "Scheduling retry while the stream is neither cancelled nor closed"); + + checkState( + adsRpcRetryTimer == null, "Scheduling retry while a retry is already pending"); + + class AdsRpcRetryTask implements Runnable { + @Override + public void run() { + adsRpcRetryTimer = null; + refreshAdsStream(); + } + } + + if (firstEdsResponseReceived) { + // Reset the backoff sequence if balancer has sent the initial response + adsRpcRetryPolicy = backoffPolicyProvider.get(); + // Retry immediately + helper.getSynchronizationContext().execute(new AdsRpcRetryTask()); + return; + } + + adsRpcRetryTimer = helper.getSynchronizationContext().schedule( + new AdsRpcRetryTask(), + adsRpcRetryPolicy.nextBackoffNanos() - retryStopwatch.elapsed(TimeUnit.NANOSECONDS), + TimeUnit.NANOSECONDS, + helper.getScheduledExecutorService()); + } + }; + + boolean cancelled; + boolean closed; + + AdsStream(AdsStreamCallback2 adsStreamCallback2) { + this.adsStreamCallback2 = adsStreamCallback2; + this.xdsRequestWriter = AggregatedDiscoveryServiceGrpc.newStub(channel).withWaitForReady() + .streamAggregatedResources(xdsResponseReader); + + checkState(adsRpcRetryTimer == null, "Creating AdsStream while retry is pending"); + // Assuming standard mode, and send EDS request only + DiscoveryRequest edsRequest = + DiscoveryRequest.newBuilder() + .setNode(Node.newBuilder() + .setMetadata(Struct.newBuilder() + .putFields( + "endpoints_required", + Value.newBuilder().setBoolValue(true).build()))) + .setTypeUrl(EDS_TYPE_URL) + // In the future, the right resource name can be obtained from CDS response. + .addResourceNames(helper.getAuthority()).build(); + helper.getChannelLogger().log(ChannelLogLevel.DEBUG, "Sending EDS request {0}", edsRequest); + xdsRequestWriter.onNext(edsRequest); + } + + AdsStream(AdsStream adsStream) { + this(adsStream.adsStreamCallback2); + } + + // run in SynchronizationContext + void cancelRpc(String message, Throwable cause) { + if (cancelled) { + return; + } + cancelled = true; + xdsRequestWriter.onError( + Status.CANCELLED.withDescription(message).withCause(cause).asRuntimeException()); + } + } + + /** + * Starts a new ADS streaming RPC. + */ + XdsComms2( + ManagedChannel channel, Helper helper, AdsStreamCallback2 adsStreamCallback2, + BackoffPolicy.Provider backoffPolicyProvider, Supplier stopwatchSupplier) { + this.channel = checkNotNull(channel, "channel"); + this.helper = checkNotNull(helper, "helper"); + this.stopwatchSupplier = checkNotNull(stopwatchSupplier, "stopwatchSupplier"); + this.adsStream = new AdsStream( + checkNotNull(adsStreamCallback2, "adsStreamCallback2")); + this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); + this.adsRpcRetryPolicy = backoffPolicyProvider.get(); + } + + // run in SynchronizationContext + void refreshAdsStream() { + checkState(!channel.isShutdown(), "channel is alreday shutdown"); + + if (adsStream.closed || adsStream.cancelled) { + cancelRetryTimer(); + adsStream = new AdsStream(adsStream); + } + } + + // run in SynchronizationContext + // TODO: Change method name to shutdown or shutdownXdsComms if that gives better semantics ( + // cancel LB RPC and clean up retry timer). + void shutdownLbRpc() { + adsStream.cancelRpc("shutdown", null); + cancelRetryTimer(); + } + + // run in SynchronizationContext + private void cancelRetryTimer() { + if (adsRpcRetryTimer != null) { + adsRpcRetryTimer.cancel(); + adsRpcRetryTimer = null; + } + } +} diff --git a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java new file mode 100644 index 00000000000..d801d735d74 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java @@ -0,0 +1,433 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.inOrder; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.protobuf.Any; +import com.google.protobuf.UInt32Value; +import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; +import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy; +import io.envoyproxy.envoy.api.v2.DiscoveryRequest; +import io.envoyproxy.envoy.api.v2.DiscoveryResponse; +import io.envoyproxy.envoy.api.v2.core.Address; +import io.envoyproxy.envoy.api.v2.core.Locality; +import io.envoyproxy.envoy.api.v2.core.SocketAddress; +import io.envoyproxy.envoy.api.v2.endpoint.Endpoint; +import io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint; +import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; +import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase; +import io.envoyproxy.envoy.type.FractionalPercent; +import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; +import io.grpc.ChannelLogger; +import io.grpc.LoadBalancer.Helper; +import io.grpc.ManagedChannel; +import io.grpc.Status; +import io.grpc.SynchronizationContext; +import io.grpc.inprocess.InProcessChannelBuilder; +import io.grpc.inprocess.InProcessServerBuilder; +import io.grpc.internal.testing.StreamRecorder; +import io.grpc.stub.StreamObserver; +import io.grpc.testing.GrpcCleanupRule; +import io.grpc.xds.LoadReportClient.LoadReportCallback; +import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.XdsComms.DropOverload; +import io.grpc.xds.XdsComms.LocalityInfo; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.ArgumentCaptor; +import org.mockito.ArgumentMatchers; +import org.mockito.Captor; +import org.mockito.InOrder; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Tests for {@link LookasideChannelLb}. + */ +@RunWith(JUnit4.class) +public class LookasideChannelLbTest { + + private static final String BALANCER_NAME = "fakeBalancerName"; + private static final String SERVICE_AUTHORITY = "test authority"; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + @Rule + public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); + + private final SynchronizationContext syncContext = new SynchronizationContext( + new Thread.UncaughtExceptionHandler() { + @Override + public void uncaughtException(Thread t, Throwable e) { + throw new AssertionError(e); + } + }); + private final StreamRecorder streamRecorder = StreamRecorder.create(); + + private final DiscoveryResponse edsResponse = + DiscoveryResponse.newBuilder() + .addResources(Any.pack(ClusterLoadAssignment.getDefaultInstance())) + .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") + .build(); + + @Mock + private Helper helper; + @Mock + private AdsStreamCallback adsStreamCallback; + @Mock + private LoadReportClient loadReportClient; + @Mock + private LocalityStore localityStore; + @Mock + private LoadStatsStore loadStatsStore; + + private ManagedChannel channel; + private StreamObserver serverResponseWriter; + + @Captor + private ArgumentCaptor> localityEndpointsMappingCaptor; + + private LookasideChannelLb lookasideChannelLb; + + @Before + public void setUp() throws Exception { + AggregatedDiscoveryServiceImplBase serviceImpl = new AggregatedDiscoveryServiceImplBase() { + @Override + public StreamObserver streamAggregatedResources( + final StreamObserver responseObserver) { + serverResponseWriter = responseObserver; + + return new StreamObserver() { + + @Override + public void onNext(DiscoveryRequest value) { + streamRecorder.onNext(value); + } + + @Override + public void onError(Throwable t) { + streamRecorder.onError(t); + } + + @Override + public void onCompleted() { + streamRecorder.onCompleted(); + responseObserver.onCompleted(); + } + }; + } + }; + + String serverName = InProcessServerBuilder.generateName(); + cleanupRule.register( + InProcessServerBuilder + .forName(serverName) + .directExecutor() + .addService(serviceImpl) + .build() + .start()); + channel = cleanupRule.register( + InProcessChannelBuilder + .forName(serverName) + .directExecutor() + .build()); + + doReturn(channel).when(helper).createResolvingOobChannel(BALANCER_NAME); + doReturn(SERVICE_AUTHORITY).when(helper).getAuthority(); + doReturn(syncContext).when(helper).getSynchronizationContext(); + doReturn(mock(ChannelLogger.class)).when(helper).getChannelLogger(); + doReturn(loadStatsStore).when(localityStore).getLoadStatsStore(); + + lookasideChannelLb = new LookasideChannelLb( + helper, adsStreamCallback, BALANCER_NAME, loadReportClient, localityStore); + + verify(helper).createResolvingOobChannel(BALANCER_NAME); + } + + @Test + public void firstAndSecondEdsResponseReceived() { + verify(adsStreamCallback, never()).onWorking(); + verify(loadReportClient, never()).startLoadReporting(any(LoadReportCallback.class)); + + // first EDS response + serverResponseWriter.onNext(edsResponse); + verify(adsStreamCallback).onWorking(); + ArgumentCaptor loadReportCallbackCaptor = + ArgumentCaptor.forClass(LoadReportCallback.class); + verify(loadReportClient).startLoadReporting(loadReportCallbackCaptor.capture()); + LoadReportCallback loadReportCallback = loadReportCallbackCaptor.getValue(); + + // second EDS response + serverResponseWriter.onNext(edsResponse); + verify(adsStreamCallback, times(1)).onWorking(); + verify(loadReportClient, times(1)).startLoadReporting(any(LoadReportCallback.class)); + + verify(localityStore, never()).updateOobMetricsReportInterval(anyLong()); + loadReportCallback.onReportResponse(1234); + verify(localityStore).updateOobMetricsReportInterval(1234); + + verify(adsStreamCallback, never()).onError(); + + lookasideChannelLb.shutdown(); + } + + @Test + public void handleDropUpdates() { + verify(localityStore, never()).updateDropPercentage( + ArgumentMatchers.>any()); + + serverResponseWriter.onNext(edsResponse); + verify(localityStore).updateDropPercentage(eq(ImmutableList.of())); + + ClusterLoadAssignment clusterLoadAssignment = ClusterLoadAssignment.newBuilder() + .setPolicy(Policy.newBuilder() + .addDropOverloads(Policy.DropOverload.newBuilder() + .setCategory("cat_1").setDropPercentage(FractionalPercent.newBuilder() + .setDenominator(DenominatorType.HUNDRED) + .setNumerator(3) + .build()) + .build()) + + .addDropOverloads(Policy.DropOverload.newBuilder() + .setCategory("cat_2").setDropPercentage(FractionalPercent.newBuilder() + .setDenominator(DenominatorType.TEN_THOUSAND) + .setNumerator(45) + .build()) + .build()) + .addDropOverloads(Policy.DropOverload.newBuilder() + .setCategory("cat_3").setDropPercentage(FractionalPercent.newBuilder() + .setDenominator(DenominatorType.MILLION) + .setNumerator(6789) + .build()) + .build()) + .build()) + .build(); + serverResponseWriter.onNext( + DiscoveryResponse.newBuilder() + .addResources(Any.pack(clusterLoadAssignment)) + .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") + .build()); + + verify(adsStreamCallback, never()).onAllDrop(); + verify(localityStore).updateDropPercentage(ImmutableList.of( + new DropOverload("cat_1", 300_00), + new DropOverload("cat_2", 45_00), + new DropOverload("cat_3", 6789))); + + + clusterLoadAssignment = ClusterLoadAssignment.newBuilder() + .setPolicy(Policy.newBuilder() + .addDropOverloads(Policy.DropOverload.newBuilder() + .setCategory("cat_1").setDropPercentage(FractionalPercent.newBuilder() + .setDenominator(DenominatorType.HUNDRED) + .setNumerator(3) + .build()) + .build()) + .addDropOverloads(Policy.DropOverload.newBuilder() + .setCategory("cat_2").setDropPercentage(FractionalPercent.newBuilder() + .setDenominator(DenominatorType.HUNDRED) + .setNumerator(101) + .build()) + .build()) + .addDropOverloads(Policy.DropOverload.newBuilder() + .setCategory("cat_3").setDropPercentage(FractionalPercent.newBuilder() + .setDenominator(DenominatorType.HUNDRED) + .setNumerator(23) + .build()) + .build()) + .build()) + .build(); + serverResponseWriter.onNext( + DiscoveryResponse.newBuilder() + .addResources(Any.pack(clusterLoadAssignment)) + .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") + .build()); + + verify(adsStreamCallback).onAllDrop(); + verify(localityStore).updateDropPercentage(ImmutableList.of( + new DropOverload("cat_1", 300_00), + new DropOverload("cat_2", 100_00_00))); + + verify(adsStreamCallback, never()).onError(); + + lookasideChannelLb.shutdown(); + } + + @Test + public void handleLocalityAssignmentUpdates() { + Locality localityProto1 = Locality.newBuilder() + .setRegion("region1").setZone("zone1").setSubZone("subzone1").build(); + LbEndpoint endpoint11 = LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("addr11").setPortValue(11)))) + .setLoadBalancingWeight(UInt32Value.of(11)) + .build(); + LbEndpoint endpoint12 = LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("addr12").setPortValue(12)))) + .setLoadBalancingWeight(UInt32Value.of(12)) + .build(); + Locality localityProto2 = Locality.newBuilder() + .setRegion("region2").setZone("zone2").setSubZone("subzone2").build(); + LbEndpoint endpoint21 = LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("addr21").setPortValue(21)))) + .setLoadBalancingWeight(UInt32Value.of(21)) + .build(); + LbEndpoint endpoint22 = LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("addr22").setPortValue(22)))) + .setLoadBalancingWeight(UInt32Value.of(22)) + .build(); + Locality localityProto3 = Locality.newBuilder() + .setRegion("region3").setZone("zone3").setSubZone("subzone3").build(); + LbEndpoint endpoint3 = LbEndpoint.newBuilder() + .setEndpoint(Endpoint.newBuilder() + .setAddress(Address.newBuilder() + .setSocketAddress(SocketAddress.newBuilder() + .setAddress("addr31").setPortValue(31)))) + .setLoadBalancingWeight(UInt32Value.of(31)) + .build(); + ClusterLoadAssignment clusterLoadAssignment = ClusterLoadAssignment.newBuilder() + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto1) + .addLbEndpoints(endpoint11) + .addLbEndpoints(endpoint12) + .setLoadBalancingWeight(UInt32Value.of(1))) + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto2) + .addLbEndpoints(endpoint21) + .addLbEndpoints(endpoint22) + .setLoadBalancingWeight(UInt32Value.of(2))) + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto3) + .addLbEndpoints(endpoint3) + .setLoadBalancingWeight(UInt32Value.of(0))) + .build(); + serverResponseWriter.onNext( + DiscoveryResponse.newBuilder() + .addResources(Any.pack(clusterLoadAssignment)) + .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") + .build()); + + XdsLocality locality1 = XdsLocality.fromLocalityProto(localityProto1); + LocalityInfo localityInfo1 = new LocalityInfo( + ImmutableList.of( + new XdsComms.LbEndpoint(endpoint11), + new XdsComms.LbEndpoint(endpoint12)), + 1, 0); + LocalityInfo localityInfo2 = new LocalityInfo( + ImmutableList.of( + new XdsComms.LbEndpoint(endpoint21), + new XdsComms.LbEndpoint(endpoint22)), + 2, 0); + XdsLocality locality2 = XdsLocality.fromLocalityProto(localityProto2); + + InOrder inOrder = inOrder(localityStore); + inOrder.verify(localityStore).updateDropPercentage(ImmutableList.of()); + inOrder.verify(localityStore).updateLocalityStore(localityEndpointsMappingCaptor.capture()); + assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( + locality1, localityInfo1, locality2, localityInfo2).inOrder(); + + verify(adsStreamCallback, never()).onError(); + + lookasideChannelLb.shutdown(); + } + + @Test + public void verifyRpcErrorPropagation() { + verify(adsStreamCallback, never()).onError(); + serverResponseWriter.onError(new RuntimeException()); + verify(adsStreamCallback).onError(); + } + + @Test + public void shutdown() { + verify(loadReportClient, never()).stopLoadReporting(); + assertThat(channel.isShutdown()).isFalse(); + + lookasideChannelLb.shutdown(); + + verify(loadReportClient).stopLoadReporting(); + assertThat(channel.isShutdown()).isTrue(); + } + + /** + * Tests load reporting is initiated after receiving the first valid EDS response from the traffic + * director, then its operation is independent of load balancing until xDS load balancer is + * shutdown. + */ + @Test + public void reportLoadAfterReceivingFirstEdsResponseUntilShutdown() { + // Simulates a syntactically incorrect EDS response. + serverResponseWriter.onNext(DiscoveryResponse.getDefaultInstance()); + verify(loadReportClient, never()).startLoadReporting(any(LoadReportCallback.class)); + verify(adsStreamCallback, never()).onWorking(); + verify(adsStreamCallback, never()).onError(); + + // Simulate a syntactically correct EDS response. + DiscoveryResponse edsResponse = + DiscoveryResponse.newBuilder() + .addResources(Any.pack(ClusterLoadAssignment.getDefaultInstance())) + .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") + .build(); + serverResponseWriter.onNext(edsResponse); + + verify(adsStreamCallback).onWorking(); + + ArgumentCaptor lrsCallbackCaptor = ArgumentCaptor.forClass(null); + verify(loadReportClient).startLoadReporting(lrsCallbackCaptor.capture()); + lrsCallbackCaptor.getValue().onReportResponse(19543); + verify(localityStore).updateOobMetricsReportInterval(19543); + + // Simulate another EDS response from the same remote balancer. + serverResponseWriter.onNext(edsResponse); + verifyNoMoreInteractions(adsStreamCallback, loadReportClient); + + // Simulate an EDS error response. + serverResponseWriter.onError(Status.ABORTED.asException()); + verify(adsStreamCallback).onError(); + + verifyNoMoreInteractions(adsStreamCallback, loadReportClient); + verify(localityStore, times(1)).updateOobMetricsReportInterval(anyLong()); // only once + } +} From 468d540bc9d60f829dccc4eff6248de375864d71 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Wed, 2 Oct 2019 09:36:42 -0700 Subject: [PATCH 057/131] SecretManager implementation for file secrets (#6173) * SecretManager implementation for file secrets (only TlsCertificate in this PR) --- .../java/io/grpc/xds/sds/SecretManager.java | 54 +++++++ .../java/io/grpc/xds/sds/SecretProvider.java | 41 +++++ .../io/grpc/xds/sds/SecretProviderMap.java | 61 ++++++++ .../sds/TlsCertificateSecretProviderMap.java | 36 +++++ ...CertificateSecretVolumeSecretProvider.java | 89 +++++++++++ .../io/grpc/xds/sds/TlsCertificateStore.java | 92 ++++++++++++ .../io/grpc/xds/sds/SecretManagerTest.java | 77 ++++++++++ .../TlsCertificateSecretProviderMapTest.java | 111 ++++++++++++++ ...ificateSecretVolumeSecretProviderTest.java | 137 +++++++++++++++++ .../grpc/xds/sds/TlsCertificateStoreTest.java | 140 ++++++++++++++++++ 10 files changed, 838 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/sds/SecretManager.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/SecretProvider.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretManager.java b/xds/src/main/java/io/grpc/xds/sds/SecretManager.java new file mode 100644 index 00000000000..45ad2b5ab9c --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/SecretManager.java @@ -0,0 +1,54 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.envoyproxy.envoy.api.v2.core.ConfigSource; +import io.grpc.Internal; + +/** + * SecretManager to manage secrets. This is used by gRPC-xds to access secrets + * and not part of the public API of gRPC + */ +// TODO(sanjaypujare): Lifecycle management for this manager and the {@link SecretProvider}s +// to be implemented using an object-pool mechanism +@Internal +public final class SecretManager { + + /** + * Finds an existing SecretProvider or creates it if it doesn't exist. + * + * @param configSource from the SdsSecretConfig + * @param name from the SdsSecretConfig + * @return the SecretProvider + */ + public SecretProvider findOrCreateTlsCertificateProvider( + ConfigSource configSource, String name) { + checkNotNull(configSource, "configSource"); + checkNotNull(name, "name"); + // for now we support only path/volume based secret provider + if (configSource.getConfigSourceSpecifierCase() + != ConfigSource.ConfigSourceSpecifierCase.PATH) { + throw new UnsupportedOperationException("Only file based secret supported"); + } + return secretVolumeCertificateProviders.findOrCreate(configSource, name); + } + + private final TlsCertificateSecretProviderMap secretVolumeCertificateProviders = + new TlsCertificateSecretProviderMap(); +} diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java new file mode 100644 index 00000000000..a03304f36c1 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import io.grpc.Internal; +import java.util.concurrent.Executor; + +/** + * A SecretProvider is a "container" or provider of a secret. This is used by gRPC-xds to access + * secrets, so is not part of the public API of gRPC. This "container" may represent a stream that + * is receiving the requested secret(s) or it could represent file-system based secret(s) that are + * dynamic. Synchronous and Asynchronous methods to access the underlying secret are available. See + * {@link SecretManager} for a note on lifecycle management + */ +@Internal +public interface SecretProvider { + + interface Callback { + void updateSecret(T secret); + } + + /** + * Registers a callback on the given executor. The callback will run when secret becomes + * available or immediately if the result is already available. + */ + void addCallback(Callback callback, Executor executor); +} diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java b/xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java new file mode 100644 index 00000000000..d9a8d97af51 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.envoyproxy.envoy.api.v2.core.ConfigSource; + +import java.util.HashMap; +import java.util.Map; + +/** + * SecretProviderMap used by SecretManager to maintain certificateProviders. + * + * @param Type of secret stored in this Map + */ +abstract class SecretProviderMap { + + private final Map> providers; + + protected SecretProviderMap() { + providers = new HashMap<>(); + } + + /** + * Finds an existing SecretProvider or creates it if it doesn't exist. + * + * @param configSource source part of the SdsSecretConfig + * @param name name of the SdsSecretConfig + * @return SecrerProvider + */ + final synchronized SecretProvider findOrCreate( + ConfigSource configSource, String name) { + checkNotNull(configSource, "configSource"); + checkNotNull(name, "name"); + + String mapKey = "" + configSource.hashCode() + "." + name; + SecretProvider provider = providers.get(mapKey); + if (provider == null) { + provider = create(configSource, name); + providers.put(mapKey, provider); + } + return provider; + } + + abstract SecretProvider create(ConfigSource configSource, String name); +} diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java new file mode 100644 index 00000000000..25d8959bc0a --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java @@ -0,0 +1,36 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.envoyproxy.envoy.api.v2.core.ConfigSource; + +final class TlsCertificateSecretProviderMap extends SecretProviderMap { + + @Override + SecretProvider create(ConfigSource configSource, String name) { + checkNotNull(configSource, "configSource"); + checkNotNull(name, "name"); + // for now we support only path/volume based secret provider + if (configSource.getConfigSourceSpecifierCase() + != ConfigSource.ConfigSourceSpecifierCase.PATH) { + throw new UnsupportedOperationException("Only file based secret supported"); + } + return new TlsCertificateSecretVolumeSecretProvider(configSource.getPath(), name); + } +} diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java new file mode 100644 index 00000000000..27f266d5ad0 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java @@ -0,0 +1,89 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import com.google.protobuf.ByteString; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Implementation of a file based secret provider. + */ +final class TlsCertificateSecretVolumeSecretProvider + implements SecretProvider { + + public static final String PEM = ".pem"; + public static final String CRT = ".crt"; + private static final Logger logger = Logger + .getLogger(TlsCertificateSecretVolumeSecretProvider.class.getName()); + private final String path; + + // for now mark it unused + @SuppressWarnings("unused") + private final String name; + + TlsCertificateSecretVolumeSecretProvider(String path, String name) { + this.path = checkNotNull(path, "path"); + this.name = checkNotNull(name, "name"); + } + + @Override + public void addCallback(final Callback callback, Executor executor) { + checkNotNull(callback, "callback"); + checkNotNull(executor, "executor"); + executor.execute(new Runnable() { + @Override + public void run() { + // as per the contract of this provider we will get the current on-disk + // contents of the files + try { + TlsCertificateStore tlsCert = get(); + callback.updateSecret(tlsCert); + } catch (ExecutionException e) { + logger.log( + Level.SEVERE, + "RuntimeException from get()", + e); + } + } + }); + } + + /** + * Gets the current contents of the private key and cert file. Assume the key has + * .pem extension and cert has .crt extension + * (needs to match mounted secrets). + */ + @VisibleForTesting + TlsCertificateStore get() throws ExecutionException { + try { + final FileInputStream pemStream = new FileInputStream(path + PEM); + final FileInputStream crtStream = new FileInputStream(path + CRT); + return new TlsCertificateStore(ByteString.readFrom(pemStream), + ByteString.readFrom(crtStream)); + } catch (IOException e) { + throw new ExecutionException(e); + } + } +} diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java new file mode 100644 index 00000000000..3cf4ef6f852 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java @@ -0,0 +1,92 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.protobuf.ByteString; +import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.core.DataSource; +import io.grpc.Internal; + +/** + * TlsCertificate's PrivateKey and Certificate are extracted into ByteString's. + * Used by the gRPC SSLContext/Protocol Negotiator and is internal. + * See {@link SecretManager} for a note on lifecycle management. + */ +@Internal +public final class TlsCertificateStore { + + private final ByteString privateKey; + private final ByteString certChain; + + private static ByteString getByteStringFromDataSource(DataSource dataSource) { + checkNotNull(dataSource); + ByteString dataSourceByteString = null; + if (dataSource.getSpecifierCase() == DataSource.SpecifierCase.INLINE_BYTES) { + dataSourceByteString = dataSource.getInlineBytes(); + } else if (dataSource.getSpecifierCase() == DataSource.SpecifierCase.INLINE_STRING) { + dataSourceByteString = dataSource.getInlineStringBytes(); + } else { + throw new UnsupportedOperationException( + "dataSource of type " + dataSource.getSpecifierCase() + " not supported"); + } + return dataSourceByteString; + } + + /** + * Creates the Store out of the TlsCertificate object of xDS. + * + * @param tlsCertificate TlsCertificate Object of xDS + */ + public TlsCertificateStore(TlsCertificate tlsCertificate) { + this( + getByteStringFromDataSource(checkNotNull(tlsCertificate).getPrivateKey()), + getByteStringFromDataSource(tlsCertificate.getCertificateChain())); + } + + /** + * Creates the Store out of 2 streams for the 2 certs on disk. + * + * @param privateKeySteam stream representing private key on disk + * @param certChain stream representing cert on disk + */ + public TlsCertificateStore(ByteString privateKeySteam, ByteString certChain) { + checkNotNull(privateKeySteam); + checkNotNull(certChain); + this.privateKey = privateKeySteam; + this.certChain = certChain; + } + + /** + * getter for private key stream. + * + * @return inputStream representing private key + */ + public ByteString getPrivateKey() { + return privateKey; + } + + /** + * getter for cert key stream. + * + * @return inputStream representing cert + */ + public ByteString getCertChain() { + return certChain; + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java new file mode 100644 index 00000000000..d0b8ff91e43 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java @@ -0,0 +1,77 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; +import io.envoyproxy.envoy.api.v2.core.ConfigSource; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link SecretManager}. + */ +@RunWith(JUnit4.class) +public class SecretManagerTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void createTest() throws IOException, ExecutionException, InterruptedException { + ConfigSource configSource = TlsCertificateSecretProviderMapTest + .createFileAndConfigSource(temporaryFolder); + + SecretManager secretManager = new SecretManager(); + SecretProvider provider = secretManager + .findOrCreateTlsCertificateProvider(configSource, "test"); + assertThat(provider).isNotNull(); + TlsCertificateStore tlsCertificateStore = + TlsCertificateSecretProviderMapTest.getValueThruCallback(provider); + assertThat(tlsCertificateStore).isNotNull(); + TlsCertificateStoreTest + .verifyKeyAndCertsWithStrings(tlsCertificateStore, "pemContents", "crtContents"); + } + + @Test + @SuppressWarnings("unused") + public void nonFilePathConfigSource() { + ConfigSource configSource = + ConfigSource.newBuilder() + .setApiConfigSource(ApiConfigSource.newBuilder().build()) + .build(); + + //thrown.expect(UnsupportedOperationException.class); + SecretManager secretManager = new SecretManager(); + try { + SecretProvider provider = secretManager + .findOrCreateTlsCertificateProvider(configSource, "test"); + Assert.fail("no exception thrown"); + } catch (UnsupportedOperationException expected) { + assertThat(expected).hasMessageThat() + .contains("Only file based secret supported"); + } + } + +} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java new file mode 100644 index 00000000000..681cab46d81 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java @@ -0,0 +1,111 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.util.concurrent.MoreExecutors; +import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; +import io.envoyproxy.envoy.api.v2.core.ConfigSource; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link TlsCertificateSecretProviderMap}. + */ +@RunWith(JUnit4.class) +public class TlsCertificateSecretProviderMapTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + /** + * Utility function for creation of test files in a temp folder. + * Used in other classes + * + * @param temporaryFolder temporary folder to use + * @return a config source representing the file based secret + * @throws IOException represents IO exception + */ + static ConfigSource createFileAndConfigSource(TemporaryFolder temporaryFolder) + throws IOException { + File filePath = TlsCertificateSecretVolumeSecretProviderTest + .createTestCertFiles(temporaryFolder); + + return ConfigSource.newBuilder() + .setPath(filePath.getPath()) + .build(); + } + + static class TestCallback implements + SecretProvider.Callback { + + TlsCertificateStore updatedSecret; + + @Override + public void updateSecret(TlsCertificateStore secret) { + updatedSecret = secret; + } + } + + /** + * Helper method to get the value thru directExecutore callback. Used by other classes. + */ + static TlsCertificateStore getValueThruCallback(SecretProvider provider) { + TestCallback testCallback = new TestCallback(); + provider.addCallback(testCallback, MoreExecutors.directExecutor()); + return testCallback.updatedSecret; + } + + + @Test + public void createTest() throws IOException, ExecutionException, InterruptedException { + ConfigSource configSource = createFileAndConfigSource(temporaryFolder); + TlsCertificateSecretProviderMap map = new TlsCertificateSecretProviderMap(); + SecretProvider provider = map.findOrCreate(configSource, "test"); + assertThat(provider).isNotNull(); + TlsCertificateStore tlsCertificateStore = getValueThruCallback(provider); + assertThat(tlsCertificateStore).isNotNull(); + TlsCertificateStoreTest + .verifyKeyAndCertsWithStrings(tlsCertificateStore, "pemContents", "crtContents"); + } + + @Test + public void nonFilePathConfigSource() { + ConfigSource configSource = + ConfigSource.newBuilder() + .setApiConfigSource(ApiConfigSource.newBuilder().build()) + .build(); + + TlsCertificateSecretProviderMap map = new TlsCertificateSecretProviderMap(); + try { + SecretProvider unused = map.findOrCreate(configSource, "test"); + Assert.fail("no exception thrown"); + } catch (UnsupportedOperationException expected) { + assertThat(expected).hasMessageThat() + .contains("Only file based secret supported"); + } + } + +} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java new file mode 100644 index 00000000000..92b33f877a7 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java @@ -0,0 +1,137 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.util.concurrent.MoreExecutors; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Writer; +import java.nio.file.Files; +import java.util.concurrent.ExecutionException; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link TlsCertificateSecretVolumeSecretProvider}. + */ +@RunWith(JUnit4.class) +public class TlsCertificateSecretVolumeSecretProviderTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + /** + * Utility function for creation of test files in a temp folder. + * + * @param temporaryFolder temporary folder to use + * @return a config source representing the file based secret + * @throws IOException represents an IO exception + */ + static File createTestCertFiles(TemporaryFolder temporaryFolder) throws IOException { + createATestCertFile(temporaryFolder, "mycert.pem", "pemContents"); + createATestCertFile(temporaryFolder, "mycert.crt", "crtContents"); + + return new File(temporaryFolder.getRoot(), "mycert"); + } + + private static void createATestCertFile( + TemporaryFolder temporaryFolder, + String s, + String pemContents) throws IOException { + File pem = temporaryFolder.newFile(s); + Writer pemFile = Files.newBufferedWriter(pem.toPath(), UTF_8); + pemFile.write(pemContents); + pemFile.close(); + } + + @Test + public void readBothFiles() throws IOException, ExecutionException, InterruptedException { + File filePath = createTestCertFiles(temporaryFolder); + TlsCertificateSecretVolumeSecretProvider provider = + new TlsCertificateSecretVolumeSecretProvider(filePath.getPath(), "test"); + + TlsCertificateStore tlsCertificateStore = provider.get(); + assertThat(tlsCertificateStore).isNotNull(); + TlsCertificateStoreTest + .verifyKeyAndCertsWithStrings(tlsCertificateStore, "pemContents", "crtContents"); + } + + private boolean listenerRun; + + @Test + public void verifyCallbackExecuted() + throws IOException, ExecutionException, InterruptedException { + // with a valid file we should get a callback + File filePath = createTestCertFiles(temporaryFolder); + TlsCertificateSecretVolumeSecretProvider provider = + new TlsCertificateSecretVolumeSecretProvider(filePath.getPath(), "test"); + + listenerRun = false; + provider.addCallback(new SecretProvider.Callback() { + + @Override + public void updateSecret(TlsCertificateStore secret) { + listenerRun = true; + } + }, MoreExecutors.directExecutor()); + assertThat(listenerRun).isTrue(); + } + + @Test + public void readMissingFile() throws IOException, ExecutionException, InterruptedException { + createATestCertFile(temporaryFolder, "mycert.pem", "pemContents"); + + // no crt file + File filePath = new File(temporaryFolder.getRoot(), "mycert"); + TlsCertificateSecretVolumeSecretProvider provider = + new TlsCertificateSecretVolumeSecretProvider(filePath.getPath(), "test"); + + try { + provider.get(); + Assert.fail("no exception thrown"); + } catch (ExecutionException expected) { + assertThat(expected.getCause()).isInstanceOf(FileNotFoundException.class); + } + } + + @Test + public void verifyCallbackNotExecuted() + throws IOException, ExecutionException, InterruptedException { + // with an invalid file we should NOT get a callback + + TlsCertificateSecretVolumeSecretProvider provider = + new TlsCertificateSecretVolumeSecretProvider("/a/b/test", "test"); + + listenerRun = false; + provider.addCallback(new SecretProvider.Callback() { + + @Override + public void updateSecret(TlsCertificateStore secret) { + listenerRun = true; + } + }, MoreExecutors.directExecutor()); + assertThat(listenerRun).isFalse(); + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java new file mode 100644 index 00000000000..c34e030c540 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java @@ -0,0 +1,140 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.protobuf.ByteString; +import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.core.DataSource; +import java.io.IOException; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link TlsCertificateStore}. + */ +@RunWith(JUnit4.class) +public class TlsCertificateStoreTest { + + static void verifyKeyAndCertsWithStrings(TlsCertificateStore tlsCertificateStore, String s1, + String s2) throws IOException { + verifyKeyAndCertsWithStrings(tlsCertificateStore.getPrivateKey(), s1); + verifyKeyAndCertsWithStrings(tlsCertificateStore.getCertChain(), s2); + } + + private static void verifyKeyAndCertsWithStrings(ByteString byteString, String s) + throws IOException { + assertThat(byteString).isNotNull(); + assertThat(byteString.toStringUtf8()).isEqualTo(s); + } + + @Test + public void convertFromTlsCertificateUsingString() throws IOException { + DataSource privateKey = + DataSource.newBuilder() + .setInlineString("test-privateKey") + .build(); + DataSource certChain = + DataSource.newBuilder() + .setInlineString("test-certChain") + .build(); + + TlsCertificate tlsCertificate = + TlsCertificate.newBuilder() + .setPrivateKey(privateKey) + .setCertificateChain(certChain) + .build(); + + TlsCertificateStore tlsCertificateStore = new TlsCertificateStore(tlsCertificate); + + verifyKeyAndCertsWithStrings(tlsCertificateStore, "test-privateKey", "test-certChain"); + } + + @Test + public void convertFromTlsCertificateUsingBytes() throws IOException { + byte[] privateKeyBytes = {1, 2, 3, 4}; + byte[] certChainBytes = {4, 3, 2, 1}; + + DataSource privateKey = + DataSource.newBuilder() + .setInlineBytes(ByteString.copyFrom(privateKeyBytes)) + .build(); + DataSource certChain = + DataSource.newBuilder() + .setInlineBytes(ByteString.copyFrom(certChainBytes)) + .build(); + + TlsCertificate tlsCertificate = + TlsCertificate.newBuilder() + .setPrivateKey(privateKey) + .setCertificateChain(certChain) + .build(); + + TlsCertificateStore tlsCertificateStore = new TlsCertificateStore(tlsCertificate); + + ByteString privateKeyByteString = tlsCertificateStore.getPrivateKey(); + assertThat(privateKeyByteString).isNotNull(); + assertThat(privateKeyByteString.toByteArray()).isEqualTo(privateKeyBytes); + + ByteString certChainByteString = tlsCertificateStore.getCertChain(); + assertThat(certChainByteString).isNotNull(); + assertThat(certChainByteString.toByteArray()).isEqualTo(certChainBytes); + } + + @Test + public void privateKeyNotSet() { + DataSource certChain = + DataSource.newBuilder() + .setInlineString("test-certChain") + .build(); + TlsCertificate tlsCertificate = + TlsCertificate.newBuilder() + .setCertificateChain(certChain) + .build(); + + try { + new TlsCertificateStore(tlsCertificate); + Assert.fail("no exception thrown"); + } catch (UnsupportedOperationException expected) { + assertThat(expected).hasMessageThat() + .contains("dataSource of type SPECIFIER_NOT_SET not supported"); + } + } + + @Test + public void certChainNotSet() { + DataSource privateKey = + DataSource.newBuilder() + .setInlineString("test-privateKey") + .build(); + TlsCertificate tlsCertificate = + TlsCertificate.newBuilder() + .setPrivateKey(privateKey) + .build(); + try { + new TlsCertificateStore(tlsCertificate); + Assert.fail("no exception thrown"); + } catch (UnsupportedOperationException expected) { + assertThat(expected).hasMessageThat() + .contains("dataSource of type SPECIFIER_NOT_SET not supported"); + } + } + +} From e1323e46d162b2675a8a0ef89e73e4987557e3bd Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Wed, 2 Oct 2019 08:32:10 -0700 Subject: [PATCH 058/131] xds: Add tlsCertificate and certificateValidationContext attributes to XdsAttributes: needed for passing those values to the SDS component --- .../main/java/io/grpc/xds/XdsAttributes.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsAttributes.java b/xds/src/main/java/io/grpc/xds/XdsAttributes.java index cca550df68a..20ba4eb3196 100644 --- a/xds/src/main/java/io/grpc/xds/XdsAttributes.java +++ b/xds/src/main/java/io/grpc/xds/XdsAttributes.java @@ -16,7 +16,9 @@ package io.grpc.xds; +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; import io.envoyproxy.envoy.api.v2.auth.SdsSecretConfig; +import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; import io.grpc.Attributes; import io.grpc.Grpc; @@ -26,11 +28,24 @@ final class XdsAttributes { /** * Attribute key for SdsSecretConfig of a subchannel. - * */ @Grpc.TransportAttr public static final Attributes.Key ATTR_SDS_CONFIG = Attributes.Key.create("io.grpc.xds.XdsAttributes.sdsSecretConfig"); + /** + * Attribute key for TlsCertificate of a subchannel. + */ + @Grpc.TransportAttr + public static final Attributes.Key ATTR_TLS_CERTIFICATE = + Attributes.Key.create("io.grpc.xds.XdsAttributes.tlsCertificate"); + + /** + * Attribute key for CertificateValidationContext of a subchannel. + */ + @Grpc.TransportAttr + public static final Attributes.Key ATTR_CERT_VALIDATION_CONTEXT = + Attributes.Key.create("io.grpc.xds.XdsAttributes.certificateValidationContext"); + private XdsAttributes() {} } From 5e814d49d1726f8ead28e62de5ff4def9271e764 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Wed, 2 Oct 2019 13:36:48 -0700 Subject: [PATCH 059/131] xds: remove the inapplicable text from a comment - as pointed out in a previous PR --- xds/src/main/java/io/grpc/xds/sds/SecretProvider.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java index a03304f36c1..a3418521d6b 100644 --- a/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java +++ b/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java @@ -23,8 +23,7 @@ * A SecretProvider is a "container" or provider of a secret. This is used by gRPC-xds to access * secrets, so is not part of the public API of gRPC. This "container" may represent a stream that * is receiving the requested secret(s) or it could represent file-system based secret(s) that are - * dynamic. Synchronous and Asynchronous methods to access the underlying secret are available. See - * {@link SecretManager} for a note on lifecycle management + * dynamic. */ @Internal public interface SecretProvider { From e9ac1b4a76fcbc3c57e83d049cb206b08bf23a06 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Wed, 2 Oct 2019 15:05:44 -0700 Subject: [PATCH 060/131] all: update modules to wait until other module's sourceSet is available (#6232) --- api/build.gradle | 2 ++ interop-testing/build.gradle | 2 ++ netty/build.gradle | 2 ++ okhttp/build.gradle | 2 ++ services/build.gradle | 2 ++ testing/build.gradle | 2 ++ xds/build.gradle | 2 ++ 7 files changed, 14 insertions(+) diff --git a/api/build.gradle b/api/build.gradle index 6703deaf390..affde080855 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -8,6 +8,8 @@ plugins { description = 'gRPC: API' +evaluationDependsOn(project(':grpc-context').path) + dependencies { compile project(':grpc-context'), libraries.errorprone, diff --git a/interop-testing/build.gradle b/interop-testing/build.gradle index 369dcc11f4b..12c571e31cc 100644 --- a/interop-testing/build.gradle +++ b/interop-testing/build.gradle @@ -13,6 +13,8 @@ configurations { alpnagent } +evaluationDependsOn(project(':grpc-context').path) + dependencies { compile project(':grpc-alts'), project(':grpc-auth'), diff --git a/netty/build.gradle b/netty/build.gradle index ad573eaaca7..c895a682a71 100644 --- a/netty/build.gradle +++ b/netty/build.gradle @@ -13,6 +13,8 @@ configurations { alpnagent } +evaluationDependsOn(project(':grpc-core').path) + dependencies { compile project(':grpc-core'), libraries.netty, diff --git a/okhttp/build.gradle b/okhttp/build.gradle index 205a6601ae7..74a8148b1d9 100644 --- a/okhttp/build.gradle +++ b/okhttp/build.gradle @@ -8,6 +8,8 @@ plugins { description = "gRPC: OkHttp" +evaluationDependsOn(project(':grpc-core').path) + dependencies { compile project(':grpc-core'), libraries.okio diff --git a/services/build.gradle b/services/build.gradle index d55b261cbce..2907c7007d6 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -16,6 +16,8 @@ description = "gRPC: Services" ] } +evaluationDependsOn(project(':grpc-core').path) + dependencies { compile project(':grpc-protobuf'), project(':grpc-stub'), diff --git a/testing/build.gradle b/testing/build.gradle index e64611d9eb1..bd8c98d286c 100644 --- a/testing/build.gradle +++ b/testing/build.gradle @@ -7,6 +7,8 @@ plugins { description = "gRPC: Testing" +evaluationDependsOn(project(':grpc-core').path) + dependencies { compile project(':grpc-core'), project(':grpc-stub'), diff --git a/xds/build.gradle b/xds/build.gradle index a8dc96da270..d7fe0ba564a 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -16,6 +16,8 @@ description = "gRPC: XDS plugin" ] } +evaluationDependsOn(project(':grpc-core').path) + dependencies { compile project(':grpc-protobuf'), project(':grpc-stub'), From 28323e2fb6a4966b520e3a19ca19f42bafc8f44c Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Wed, 2 Oct 2019 15:13:39 -0700 Subject: [PATCH 061/131] xds: plumbing restructured xds loadbalancer Moved `ManagedChannel initLbChannel(Helper helper, String balancerName)` out of `LookasideChannelLb` because `LoadReportClientImpl` need channel be initialized already. Migration will be in an upcoming PR. --- .../java/io/grpc/xds/LookasideChannelLb.java | 43 ++++++----------- .../main/java/io/grpc/xds/LookasideLb.java | 46 ++++++++++++++++++- .../java/io/grpc/xds/XdsLoadBalancer2.java | 19 +++++++- .../io/grpc/xds/LookasideChannelLbTest.java | 6 +-- .../java/io/grpc/xds/LookasideLbTest.java | 24 ++++++++++ 5 files changed, 103 insertions(+), 35 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java index d0b7fb0c7e3..7c33215ee8c 100644 --- a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java +++ b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java @@ -17,7 +17,6 @@ package io.grpc.xds; import static com.google.common.base.Preconditions.checkArgument; -import static java.util.logging.Level.FINEST; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableList; @@ -29,7 +28,6 @@ import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; import io.grpc.LoadBalancer; import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; import io.grpc.Status; import io.grpc.internal.ExponentialBackoffPolicy; import io.grpc.internal.GrpcUtil; @@ -39,7 +37,6 @@ import io.grpc.xds.XdsComms.LocalityInfo; import java.util.ArrayList; import java.util.List; -import java.util.logging.Logger; /** * A load balancer that has a lookaside channel. This layer of load balancer creates a channel to @@ -52,14 +49,27 @@ final class LookasideChannelLb extends LoadBalancer { private final LoadReportClient lrsClient; private final XdsComms2 xdsComms2; + LookasideChannelLb( + Helper helper, AdsStreamCallback adsCallback, ManagedChannel lbChannel, + LocalityStore localityStore) { + this( + helper, + adsCallback, + lbChannel, + new LoadReportClientImpl( + lbChannel, helper, GrpcUtil.STOPWATCH_SUPPLIER, new ExponentialBackoffPolicy.Provider(), + localityStore.getLoadStatsStore()), + localityStore); + } + @VisibleForTesting LookasideChannelLb( Helper helper, AdsStreamCallback adsCallback, - String balancerName, + ManagedChannel lbChannel, LoadReportClient lrsClient, final LocalityStore localityStore) { - lbChannel = initLbChannel(helper, balancerName); + this.lbChannel = lbChannel; LoadReportCallback lrsCallback = new LoadReportCallback() { @Override @@ -101,29 +111,6 @@ private static int rateInMillion(FractionalPercent fractionalPercent) { return numerator; } - private static ManagedChannel initLbChannel(Helper helper, String balancerName) { - ManagedChannel channel; - try { - channel = helper.createResolvingOobChannel(balancerName); - } catch (UnsupportedOperationException uoe) { - // Temporary solution until createResolvingOobChannel is implemented - // FIXME (https://github.com/grpc/grpc-java/issues/5495) - Logger logger = Logger.getLogger(LookasideChannelLb.class.getName()); - if (logger.isLoggable(FINEST)) { - logger.log( - FINEST, - "createResolvingOobChannel() not supported by the helper: " + helper, - uoe); - logger.log( - FINEST, - "creating oob channel for target {0} using default ManagedChannelBuilder", - balancerName); - } - channel = ManagedChannelBuilder.forTarget(balancerName).build(); - } - return channel; - } - @Override public void handleNameResolutionError(Status error) { // NO-OP? diff --git a/xds/src/main/java/io/grpc/xds/LookasideLb.java b/xds/src/main/java/io/grpc/xds/LookasideLb.java index 78722a66d1a..3f24d7c77c4 100644 --- a/xds/src/main/java/io/grpc/xds/LookasideLb.java +++ b/xds/src/main/java/io/grpc/xds/LookasideLb.java @@ -17,18 +17,23 @@ package io.grpc.xds; import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.logging.Level.FINEST; import com.google.common.annotations.VisibleForTesting; import io.grpc.Attributes; import io.grpc.LoadBalancer; import io.grpc.LoadBalancerProvider; import io.grpc.LoadBalancerRegistry; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; import io.grpc.NameResolver.ConfigOrError; import io.grpc.util.ForwardingLoadBalancer; import io.grpc.util.GracefulSwitchLoadBalancer; +import io.grpc.xds.LocalityStore.LocalityStoreImpl; import io.grpc.xds.XdsComms.AdsStreamCallback; import io.grpc.xds.XdsLoadBalancerProvider.XdsConfig; import java.util.Map; +import java.util.logging.Logger; /** Lookaside load balancer that handles balancer name changes. */ final class LookasideLb extends ForwardingLoadBalancer { @@ -40,7 +45,12 @@ final class LookasideLb extends ForwardingLoadBalancer { private String balancerName; - // TODO(zdapeng): Add LookasideLb(Helper helper, AdsCallback adsCallback) with default factory + LookasideLb(Helper lookasideLbHelper, AdsStreamCallback adsCallback) { + this( + lookasideLbHelper, adsCallback, new LookasideChannelLbFactoryImpl(), + LoadBalancerRegistry.getDefaultRegistry()); + } + @VisibleForTesting LookasideLb( Helper lookasideLbHelper, @@ -112,4 +122,38 @@ public LoadBalancer newLoadBalancer(Helper helper) { interface LookasideChannelLbFactory { LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback, String balancerName); } + + private static final class LookasideChannelLbFactoryImpl implements LookasideChannelLbFactory { + + @Override + public LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback, + String balancerName) { + return new LookasideChannelLb( + helper, adsCallback, initLbChannel(helper, balancerName), + new LocalityStoreImpl(helper, LoadBalancerRegistry.getDefaultRegistry())); + } + + private static ManagedChannel initLbChannel(Helper helper, String balancerName) { + ManagedChannel channel; + try { + channel = helper.createResolvingOobChannel(balancerName); + } catch (UnsupportedOperationException uoe) { + // Temporary solution until createResolvingOobChannel is implemented + // FIXME (https://github.com/grpc/grpc-java/issues/5495) + Logger logger = Logger.getLogger(LookasideChannelLb.class.getName()); + if (logger.isLoggable(FINEST)) { + logger.log( + FINEST, + "createResolvingOobChannel() not supported by the helper: " + helper, + uoe); + logger.log( + FINEST, + "creating oob channel for target {0} using default ManagedChannelBuilder", + balancerName); + } + channel = ManagedChannelBuilder.forTarget(balancerName).build(); + } + return channel; + } + } } diff --git a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java index 11df68f39fd..64bd635afdb 100644 --- a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java @@ -83,7 +83,10 @@ public void onAllDrop() { private boolean adsWorked; private boolean childPolicyHasBeenReady; - // TODO(zdapeng): Add XdsLoadBalancer2(Helper helper) with default factories + XdsLoadBalancer2(Helper helper) { + this(helper, new LookasideLbFactoryImpl(), new FallbackLbFactory()); + } + @VisibleForTesting XdsLoadBalancer2( Helper helper, @@ -245,4 +248,18 @@ public void updateBalancingState(ConnectivityState newState, SubchannelPicker ne interface LookasideLbFactory { LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback); } + + private static final class LookasideLbFactoryImpl implements LookasideLbFactory { + @Override + public LoadBalancer newLoadBalancer(Helper lookasideLbHelper, AdsStreamCallback adsCallback) { + return new LookasideLb(lookasideLbHelper, adsCallback); + } + } + + private static final class FallbackLbFactory extends LoadBalancer.Factory { + @Override + public LoadBalancer newLoadBalancer(Helper helper) { + return new FallbackLb(helper); + } + } } diff --git a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java index d801d735d74..2f4fe4fa77f 100644 --- a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java +++ b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java @@ -78,7 +78,6 @@ @RunWith(JUnit4.class) public class LookasideChannelLbTest { - private static final String BALANCER_NAME = "fakeBalancerName"; private static final String SERVICE_AUTHORITY = "test authority"; @Rule @@ -163,16 +162,13 @@ public void onCompleted() { .directExecutor() .build()); - doReturn(channel).when(helper).createResolvingOobChannel(BALANCER_NAME); doReturn(SERVICE_AUTHORITY).when(helper).getAuthority(); doReturn(syncContext).when(helper).getSynchronizationContext(); doReturn(mock(ChannelLogger.class)).when(helper).getChannelLogger(); doReturn(loadStatsStore).when(localityStore).getLoadStatsStore(); lookasideChannelLb = new LookasideChannelLb( - helper, adsStreamCallback, BALANCER_NAME, loadReportClient, localityStore); - - verify(helper).createResolvingOobChannel(BALANCER_NAME); + helper, adsStreamCallback, channel, loadReportClient, localityStore); } @Test diff --git a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java index a8a183fbd2a..9a13cf52e97 100644 --- a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java +++ b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static io.grpc.ConnectivityState.CONNECTING; import static io.grpc.LoadBalancer.ATTR_LOAD_BALANCING_CONFIG; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -157,4 +158,27 @@ public void handleChildPolicyChangeThenBalancerNameChangeThenChildPolicyChange() lookasideLb.shutdown(); verify(balancer2).shutdown(); } + + @Test + public void handleResolvedAddress_createLbChannel() + throws Exception { + // Test balancer created with the default real LookasideChannelLbFactory + lookasideLb = new LookasideLb(helper, mock(AdsStreamCallback.class)); + String lbConfigRaw11 = "{'balancerName' : 'dns:///balancer1.example.com:8080'}" + .replace("'", "\""); + @SuppressWarnings("unchecked") + Map lbConfig11 = (Map) JsonParser.parse(lbConfigRaw11); + ResolvedAddresses resolvedAddresses = ResolvedAddresses.newBuilder() + .setAddresses(ImmutableList.of()) + .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig11).build()) + .build(); + + verify(helper, never()).createResolvingOobChannel(anyString()); + try { + lookasideLb.handleResolvedAddresses(resolvedAddresses); + } catch (RuntimeException e) { + // Expected because helper is a mock and helper.createResolvingOobChannel() returns null. + } + verify(helper).createResolvingOobChannel("dns:///balancer1.example.com:8080"); + } } From 90b3c88fe21a9166c00c4d03d5994df0164b11fc Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Thu, 3 Oct 2019 15:58:18 -0700 Subject: [PATCH 062/131] api: avoid infinite loop in handleResolvedAddresses If a `LoadBalancer` implementation does not override `handleResolvedAddressGroups()`, or overrides `handleResolvedAddressGroups()` but calls `super.handleResolvedAddressGroups()` at the beginning or the end, it will be trapped in an infinite loop. --- api/src/main/java/io/grpc/LoadBalancer.java | 16 ++++++--- .../test/java/io/grpc/LoadBalancerTest.java | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/io/grpc/LoadBalancer.java b/api/src/main/java/io/grpc/LoadBalancer.java index 612d25151fc..ebae08b23cc 100644 --- a/api/src/main/java/io/grpc/LoadBalancer.java +++ b/api/src/main/java/io/grpc/LoadBalancer.java @@ -117,6 +117,8 @@ public abstract class LoadBalancer { public static final Attributes.Key> ATTR_LOAD_BALANCING_CONFIG = Attributes.Key.create("io.grpc.LoadBalancer.loadBalancingConfig"); + private int recursionCount; + /** * Handles newly resolved server groups and metadata attributes from name resolution system. * {@code servers} contained in {@link EquivalentAddressGroup} should be considered equivalent @@ -133,8 +135,11 @@ public abstract class LoadBalancer { public void handleResolvedAddressGroups( List servers, @NameResolver.ResolutionResultAttr Attributes attributes) { - handleResolvedAddresses( - ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(attributes).build()); + if (recursionCount++ == 0) { + handleResolvedAddresses( + ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(attributes).build()); + } + recursionCount = 0; } /** @@ -149,8 +154,11 @@ public void handleResolvedAddressGroups( */ @SuppressWarnings("deprecation") public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { - handleResolvedAddressGroups( - resolvedAddresses.getAddresses(), resolvedAddresses.getAttributes()); + if (recursionCount++ == 0) { + handleResolvedAddressGroups( + resolvedAddresses.getAddresses(), resolvedAddresses.getAttributes()); + } + recursionCount = 0; } /** diff --git a/api/src/test/java/io/grpc/LoadBalancerTest.java b/api/src/test/java/io/grpc/LoadBalancerTest.java index e1a7b9a5d7d..6bda67cd4d2 100644 --- a/api/src/test/java/io/grpc/LoadBalancerTest.java +++ b/api/src/test/java/io/grpc/LoadBalancerTest.java @@ -25,6 +25,7 @@ import io.grpc.LoadBalancer.ResolvedAddresses; import io.grpc.LoadBalancer.Subchannel; import java.net.SocketAddress; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.atomic.AtomicReference; @@ -360,6 +361,41 @@ public void shutdown() { assertThat(attrsCapture.get()).isEqualTo(attrs); } + @Deprecated + @Test + public void handleResolvedAddresses_noInfiniteLoop() { + final List> serversCapture = new ArrayList<>(); + final List attrsCapture = new ArrayList<>(); + + LoadBalancer balancer = new LoadBalancer() { + @Override + public void handleResolvedAddressGroups( + List servers, Attributes attrs) { + serversCapture.add(servers); + attrsCapture.add(attrs); + super.handleResolvedAddressGroups(servers, attrs); + } + + @Override + public void handleNameResolutionError(Status error) { + } + + @Override + public void shutdown() { + } + }; + + List servers = Arrays.asList( + new EquivalentAddressGroup(new SocketAddress(){}), + new EquivalentAddressGroup(new SocketAddress(){})); + balancer.handleResolvedAddresses( + ResolvedAddresses.newBuilder().setAddresses(servers).setAttributes(attrs).build()); + assertThat(serversCapture).hasSize(1); + assertThat(attrsCapture).hasSize(1); + assertThat(serversCapture.get(0)).isEqualTo(servers); + assertThat(attrsCapture.get(0)).isEqualTo(attrs); + } + private static class NoopHelper extends LoadBalancer.Helper { @Override public ManagedChannel createOobChannel(EquivalentAddressGroup eag, String authority) { From dba7e9c36fd8bf43daa59c737f2f8157509e47fc Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Thu, 3 Oct 2019 15:58:53 -0700 Subject: [PATCH 063/131] xds: migrate to restructured xds loadbalancer * Deleted: + XdsLoadBalancer + XdsLbState + XdsComms + Their test classes (except XdsCommsTest) * Moved/Renamed: + AdsStreamCallback -> LookasideChannelCallback + AdsStreamCallback2 -> AdsStreamCallback + XdsComms.LocalityInfo -> ClusterLoadAssignmentData.LocalityInfo + XdsComms.LbEndpoint -> ClusterLoadAssignmentData.LbEndpoint + XdsComms.DropOverload -> ClusterLoadAssignmentData.DropOverload + XdsLocality -> ClusterLoadAssignmentData.XdsLocality * XdsComms2 is not renamed because it's temporary. * XdsLoadBalancer2 is not renamed because otherwise the diff is hard to read. --- .../grpc/xds/ClusterLoadAssignmentData.java | 210 +++++ .../java/io/grpc/xds/LoadReportClient.java | 4 +- .../io/grpc/xds/LoadReportClientImpl.java | 2 +- .../main/java/io/grpc/xds/LoadStatsStore.java | 9 +- .../java/io/grpc/xds/LoadStatsStoreImpl.java | 1 + .../main/java/io/grpc/xds/LocalityStore.java | 5 +- .../java/io/grpc/xds/LookasideChannelLb.java | 87 +- .../main/java/io/grpc/xds/LookasideLb.java | 24 +- xds/src/main/java/io/grpc/xds/XdsComms.java | 461 ---------- xds/src/main/java/io/grpc/xds/XdsComms2.java | 30 +- xds/src/main/java/io/grpc/xds/XdsLbState.java | 115 --- .../java/io/grpc/xds/XdsLoadBalancer.java | 479 ----------- .../java/io/grpc/xds/XdsLoadBalancer2.java | 14 +- .../io/grpc/xds/XdsLoadBalancerProvider.java | 4 +- .../main/java/io/grpc/xds/XdsLocality.java | 94 -- ...ava => ClusterLoadAssignmentDataTest.java} | 11 +- .../java/io/grpc/xds/FallbackManagerTest.java | 285 ------ .../io/grpc/xds/LoadStatsStoreImplTest.java | 4 +- .../java/io/grpc/xds/LocalityStoreTest.java | 7 +- .../io/grpc/xds/LookasideChannelLbTest.java | 53 +- .../java/io/grpc/xds/LookasideLbTest.java | 9 +- .../test/java/io/grpc/xds/XdsCommsTest.java | 263 +----- .../test/java/io/grpc/xds/XdsLbStateTest.java | 156 ---- .../io/grpc/xds/XdsLoadBalancer2Test.java | 23 +- .../java/io/grpc/xds/XdsLoadBalancerTest.java | 812 ------------------ .../grpc/xds/XdsLoadBalancerWithLrsTest.java | 416 --------- 26 files changed, 415 insertions(+), 3163 deletions(-) create mode 100644 xds/src/main/java/io/grpc/xds/ClusterLoadAssignmentData.java delete mode 100644 xds/src/main/java/io/grpc/xds/XdsComms.java delete mode 100644 xds/src/main/java/io/grpc/xds/XdsLbState.java delete mode 100644 xds/src/main/java/io/grpc/xds/XdsLoadBalancer.java delete mode 100644 xds/src/main/java/io/grpc/xds/XdsLocality.java rename xds/src/test/java/io/grpc/xds/{XdsLocalityTest.java => ClusterLoadAssignmentDataTest.java} (88%) delete mode 100644 xds/src/test/java/io/grpc/xds/FallbackManagerTest.java delete mode 100644 xds/src/test/java/io/grpc/xds/XdsLbStateTest.java delete mode 100644 xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java delete mode 100644 xds/src/test/java/io/grpc/xds/XdsLoadBalancerWithLrsTest.java diff --git a/xds/src/main/java/io/grpc/xds/ClusterLoadAssignmentData.java b/xds/src/main/java/io/grpc/xds/ClusterLoadAssignmentData.java new file mode 100644 index 00000000000..e2bb482259a --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/ClusterLoadAssignmentData.java @@ -0,0 +1,210 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.MoreObjects; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import io.envoyproxy.envoy.api.v2.core.SocketAddress; +import io.grpc.EquivalentAddressGroup; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * Contains data types for ClusterLoadAssignment. + */ +final class ClusterLoadAssignmentData { + + /** + * An {@code XdsLocality} object is simply a POJO representation for {@link + * io.envoyproxy.envoy.api.v2.core.Locality}, with only details needed for {@link + * XdsLoadBalancer2}. + */ + static final class XdsLocality { + private final String region; + private final String zone; + private final String subzone; + + /** Must only be used for testing. */ + @VisibleForTesting + XdsLocality(String region, String zone, String subzone) { + this.region = region; + this.zone = zone; + this.subzone = subzone; + } + + static XdsLocality fromLocalityProto(io.envoyproxy.envoy.api.v2.core.Locality locality) { + return new XdsLocality( + /* region = */ locality.getRegion(), + /* zone = */ locality.getZone(), + /* subzone = */ locality.getSubZone()); + } + + io.envoyproxy.envoy.api.v2.core.Locality toLocalityProto() { + return io.envoyproxy.envoy.api.v2.core.Locality.newBuilder() + .setRegion(region) + .setZone(zone) + .setSubZone(subzone) + .build(); + } + + String getRegion() { + return region; + } + + String getZone() { + return zone; + } + + String getSubzone() { + return subzone; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + XdsLocality locality = (XdsLocality) o; + return Objects.equal(region, locality.region) + && Objects.equal(zone, locality.zone) + && Objects.equal(subzone, locality.subzone); + } + + @Override + public int hashCode() { + return Objects.hashCode(region, zone, subzone); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("region", region) + .add("zone", zone) + .add("subzone", subzone) + .toString(); + } + } + + /** + * Information about the locality from EDS response. + */ + static final class LocalityInfo { + final List eags; + final List endPointWeights; + final int localityWeight; + final int priority; + + LocalityInfo(Collection lbEndPoints, int localityWeight, int priority) { + List eags = new ArrayList<>(lbEndPoints.size()); + List endPointWeights = new ArrayList<>(lbEndPoints.size()); + for (LbEndpoint lbEndPoint : lbEndPoints) { + eags.add(lbEndPoint.eag); + endPointWeights.add(lbEndPoint.endPointWeight); + } + this.eags = Collections.unmodifiableList(eags); + this.endPointWeights = Collections.unmodifiableList(new ArrayList<>(endPointWeights)); + this.localityWeight = localityWeight; + this.priority = priority; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + LocalityInfo that = (LocalityInfo) o; + return localityWeight == that.localityWeight + && priority == that.priority + && Objects.equal(eags, that.eags) + && Objects.equal(endPointWeights, that.endPointWeights); + } + + @Override + public int hashCode() { + return Objects.hashCode(eags, endPointWeights, localityWeight, priority); + } + } + + static final class LbEndpoint { + final EquivalentAddressGroup eag; + final int endPointWeight; + + LbEndpoint(io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint lbEndpointProto) { + this( + new EquivalentAddressGroup(ImmutableList.of(fromEnvoyProtoAddress(lbEndpointProto))), + lbEndpointProto.getLoadBalancingWeight().getValue()); + } + + @VisibleForTesting + LbEndpoint(EquivalentAddressGroup eag, int endPointWeight) { + this.eag = eag; + this.endPointWeight = endPointWeight; + } + + private static java.net.SocketAddress fromEnvoyProtoAddress( + io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint lbEndpointProto) { + SocketAddress socketAddress = lbEndpointProto.getEndpoint().getAddress().getSocketAddress(); + return new InetSocketAddress(socketAddress.getAddress(), socketAddress.getPortValue()); + } + } + + static final class DropOverload { + final String category; + final int dropsPerMillion; + + DropOverload(String category, int dropsPerMillion) { + this.category = category; + this.dropsPerMillion = dropsPerMillion; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + DropOverload that = (DropOverload) o; + return dropsPerMillion == that.dropsPerMillion && Objects.equal(category, that.category); + } + + @Override + public int hashCode() { + return Objects.hashCode(category, dropsPerMillion); + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("category", category) + .add("dropsPerMillion", dropsPerMillion) + .toString(); + } + } +} diff --git a/xds/src/main/java/io/grpc/xds/LoadReportClient.java b/xds/src/main/java/io/grpc/xds/LoadReportClient.java index 6c7b39dee45..cdab17e1cff 100644 --- a/xds/src/main/java/io/grpc/xds/LoadReportClient.java +++ b/xds/src/main/java/io/grpc/xds/LoadReportClient.java @@ -37,7 +37,7 @@ interface LoadReportClient { * no-op. * *

This method is not thread-safe and should be called from the same synchronized context - * returned by {@link XdsLoadBalancer.Helper#getSynchronizationContext}. + * returned by {@link XdsLoadBalancer2.Helper#getSynchronizationContext}. * * @param callback containing methods to be invoked for passing information received from load * reporting responses to xDS load balancer. @@ -49,7 +49,7 @@ interface LoadReportClient { * {@link LoadReportClient} is no-op. * *

This method is not thread-safe and should be called from the same synchronized context - * returned by {@link XdsLoadBalancer.Helper#getSynchronizationContext}. + * returned by {@link XdsLoadBalancer2.Helper#getSynchronizationContext}. */ void stopLoadReporting(); diff --git a/xds/src/main/java/io/grpc/xds/LoadReportClientImpl.java b/xds/src/main/java/io/grpc/xds/LoadReportClientImpl.java index d57377e1863..753b9e27413 100644 --- a/xds/src/main/java/io/grpc/xds/LoadReportClientImpl.java +++ b/xds/src/main/java/io/grpc/xds/LoadReportClientImpl.java @@ -53,7 +53,7 @@ * Client of xDS load reporting service. * *

Methods in this class are expected to be called in the same synchronized context that {@link - * XdsLoadBalancer.Helper#getSynchronizationContext} returns. + * XdsLoadBalancer2.Helper#getSynchronizationContext} returns. */ @NotThreadSafe final class LoadReportClientImpl implements LoadReportClient { diff --git a/xds/src/main/java/io/grpc/xds/LoadStatsStore.java b/xds/src/main/java/io/grpc/xds/LoadStatsStore.java index b45f4a6fc5f..5c27e464154 100644 --- a/xds/src/main/java/io/grpc/xds/LoadStatsStore.java +++ b/xds/src/main/java/io/grpc/xds/LoadStatsStore.java @@ -17,6 +17,7 @@ package io.grpc.xds; import io.envoyproxy.envoy.api.v2.endpoint.ClusterStats; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import javax.annotation.Nullable; /** @@ -26,7 +27,7 @@ * (i.e., Google backends) are aggregated in locality granularity (i.e., Google cluster) while the * numbers of dropped calls are aggregated in cluster granularity. * - *

An {@code LoadStatsStore} lives the same span of lifecycle as {@link XdsLoadBalancer} and + *

An {@code LoadStatsStore} lives the same span of lifecycle as {@link XdsLoadBalancer2} and * only tracks loads for localities exposed by remote traffic director. A proper usage should be * *

    @@ -60,7 +61,7 @@ interface LoadStatsStore { * reporting. * *

    This method is not thread-safe and should be called from the same synchronized context - * returned by {@link XdsLoadBalancer.Helper#getSynchronizationContext}. + * returned by {@link XdsLoadBalancer2.Helper#getSynchronizationContext}. */ ClusterStats generateLoadReport(); @@ -72,7 +73,7 @@ interface LoadStatsStore { * balancer discovery responses before recording loads for those localities. * *

    This method is not thread-safe and should be called from the same synchronized context - * returned by {@link XdsLoadBalancer.Helper#getSynchronizationContext}. + * returned by {@link XdsLoadBalancer2.Helper#getSynchronizationContext}. */ void addLocality(XdsLocality locality); @@ -87,7 +88,7 @@ interface LoadStatsStore { * waste and keep including zero-load upstream locality stats in generated load reports. * *

    This method is not thread-safe and should be called from the same synchronized context - * returned by {@link XdsLoadBalancer.Helper#getSynchronizationContext}. + * returned by {@link XdsLoadBalancer2.Helper#getSynchronizationContext}. */ void removeLocality(XdsLocality locality); diff --git a/xds/src/main/java/io/grpc/xds/LoadStatsStoreImpl.java b/xds/src/main/java/io/grpc/xds/LoadStatsStoreImpl.java index c3fa05cdff6..5722899dc60 100644 --- a/xds/src/main/java/io/grpc/xds/LoadStatsStoreImpl.java +++ b/xds/src/main/java/io/grpc/xds/LoadStatsStoreImpl.java @@ -26,6 +26,7 @@ import io.envoyproxy.envoy.api.v2.endpoint.UpstreamLocalityStats; import io.grpc.xds.ClientLoadCounter.ClientLoadSnapshot; import io.grpc.xds.ClientLoadCounter.MetricValue; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; diff --git a/xds/src/main/java/io/grpc/xds/LocalityStore.java b/xds/src/main/java/io/grpc/xds/LocalityStore.java index f8d3c8ad18a..50e89242686 100644 --- a/xds/src/main/java/io/grpc/xds/LocalityStore.java +++ b/xds/src/main/java/io/grpc/xds/LocalityStore.java @@ -44,11 +44,12 @@ import io.grpc.xds.ClientLoadCounter.LoadRecordingSubchannelPicker; import io.grpc.xds.ClientLoadCounter.MetricsObservingSubchannelPicker; import io.grpc.xds.ClientLoadCounter.MetricsRecordingListener; +import io.grpc.xds.ClusterLoadAssignmentData.DropOverload; +import io.grpc.xds.ClusterLoadAssignmentData.LocalityInfo; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import io.grpc.xds.InterLocalityPicker.WeightedChildPicker; import io.grpc.xds.OrcaOobUtil.OrcaReportingConfig; import io.grpc.xds.OrcaOobUtil.OrcaReportingHelperWrapper; -import io.grpc.xds.XdsComms.DropOverload; -import io.grpc.xds.XdsComms.LocalityInfo; import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; import java.util.ArrayList; import java.util.Collections; diff --git a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java index 7c33215ee8c..37947bbb87e 100644 --- a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java +++ b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java @@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; -import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload; import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; import io.envoyproxy.envoy.type.FractionalPercent; import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; @@ -31,10 +30,12 @@ import io.grpc.Status; import io.grpc.internal.ExponentialBackoffPolicy; import io.grpc.internal.GrpcUtil; +import io.grpc.xds.ClusterLoadAssignmentData.DropOverload; +import io.grpc.xds.ClusterLoadAssignmentData.LbEndpoint; +import io.grpc.xds.ClusterLoadAssignmentData.LocalityInfo; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import io.grpc.xds.LoadReportClient.LoadReportCallback; -import io.grpc.xds.XdsComms.AdsStreamCallback; -import io.grpc.xds.XdsComms.LbEndpoint; -import io.grpc.xds.XdsComms.LocalityInfo; +import io.grpc.xds.XdsComms2.AdsStreamCallback; import java.util.ArrayList; import java.util.List; @@ -50,11 +51,11 @@ final class LookasideChannelLb extends LoadBalancer { private final XdsComms2 xdsComms2; LookasideChannelLb( - Helper helper, AdsStreamCallback adsCallback, ManagedChannel lbChannel, + Helper helper, LookasideChannelCallback lookasideChannelCallback, ManagedChannel lbChannel, LocalityStore localityStore) { this( helper, - adsCallback, + lookasideChannelCallback, lbChannel, new LoadReportClientImpl( lbChannel, helper, GrpcUtil.STOPWATCH_SUPPLIER, new ExponentialBackoffPolicy.Provider(), @@ -65,7 +66,7 @@ final class LookasideChannelLb extends LoadBalancer { @VisibleForTesting LookasideChannelLb( Helper helper, - AdsStreamCallback adsCallback, + LookasideChannelCallback lookasideChannelCallback, ManagedChannel lbChannel, LoadReportClient lrsClient, final LocalityStore localityStore) { @@ -79,10 +80,10 @@ public void onReportResponse(long reportIntervalNano) { }; this.lrsClient = lrsClient; - AdsStreamCallback2 adsCallback2 = new AdsStreamCallback2Impl( - adsCallback, lrsClient, lrsCallback, localityStore) ; + AdsStreamCallback adsCallback = new AdsStreamCallbackImpl( + lookasideChannelCallback, lrsClient, lrsCallback, localityStore) ; xdsComms2 = new XdsComms2( - lbChannel, helper, adsCallback2, new ExponentialBackoffPolicy.Provider(), + lbChannel, helper, adsCallback, new ExponentialBackoffPolicy.Provider(), GrpcUtil.STOPWATCH_SUPPLIER); } @@ -123,30 +124,18 @@ public void shutdown() { lbChannel.shutdown(); } - // TODO(zdapeng): The old AdsStreamCallback will be renamed to LookasideChannelCallback, - // and AdsStreamCallback2 will be renamed to AdsStreamCallback - /** - * Callback on ADS stream events. The callback methods should be called in a proper {@link - * io.grpc.SynchronizationContext}. - */ - interface AdsStreamCallback2 { - void onEdsResponse(ClusterLoadAssignment clusterLoadAssignment); - - void onError(); - } - - private static final class AdsStreamCallback2Impl implements AdsStreamCallback2 { + private static final class AdsStreamCallbackImpl implements AdsStreamCallback { - final AdsStreamCallback adsCallback; + final LookasideChannelCallback lookasideChannelCallback; final LoadReportClient lrsClient; final LoadReportCallback lrsCallback; final LocalityStore localityStore; boolean firstEdsResponseReceived; - AdsStreamCallback2Impl( - AdsStreamCallback adsCallback, LoadReportClient lrsClient, LoadReportCallback lrsCallback, - LocalityStore localityStore) { - this.adsCallback = adsCallback; + AdsStreamCallbackImpl( + LookasideChannelCallback lookasideChannelCallback, LoadReportClient lrsClient, + LoadReportCallback lrsCallback, LocalityStore localityStore) { + this.lookasideChannelCallback = lookasideChannelCallback; this.lrsClient = lrsClient; this.lrsCallback = lrsCallback; this.localityStore = localityStore; @@ -156,25 +145,22 @@ private static final class AdsStreamCallback2Impl implements AdsStreamCallback2 public void onEdsResponse(ClusterLoadAssignment clusterLoadAssignment) { if (!firstEdsResponseReceived) { firstEdsResponseReceived = true; - adsCallback.onWorking(); + lookasideChannelCallback.onWorking(); lrsClient.startLoadReporting(lrsCallback); } - List dropOverloadsProto = + List dropOverloadsProto = clusterLoadAssignment.getPolicy().getDropOverloadsList(); - ImmutableList.Builder dropOverloadsBuilder - = ImmutableList.builder(); - for (ClusterLoadAssignment.Policy.DropOverload dropOverload - : dropOverloadsProto) { + ImmutableList.Builder dropOverloadsBuilder = ImmutableList.builder(); + for (ClusterLoadAssignment.Policy.DropOverload dropOverload : dropOverloadsProto) { int rateInMillion = rateInMillion(dropOverload.getDropPercentage()); - dropOverloadsBuilder.add(new XdsComms.DropOverload( - dropOverload.getCategory(), rateInMillion)); + dropOverloadsBuilder.add(new DropOverload(dropOverload.getCategory(), rateInMillion)); if (rateInMillion == 1000_000) { - adsCallback.onAllDrop(); + lookasideChannelCallback.onAllDrop(); break; } } - ImmutableList dropOverloads = dropOverloadsBuilder.build(); + ImmutableList dropOverloads = dropOverloadsBuilder.build(); localityStore.updateDropPercentage(dropOverloads); List localities = clusterLoadAssignment.getEndpointsList(); @@ -203,7 +189,30 @@ public void onEdsResponse(ClusterLoadAssignment clusterLoadAssignment) { @Override public void onError() { - adsCallback.onError(); + lookasideChannelCallback.onError(); } } + + + /** + * Callback on ADS stream events. The callback methods should be called in a proper {@link + * io.grpc.SynchronizationContext}. + */ + interface LookasideChannelCallback { + + /** + * Once the response observer receives the first response. + */ + void onWorking(); + + /** + * Once an error occurs in ADS stream. + */ + void onError(); + + /** + * Once receives a response indicating that 100% of calls should be dropped. + */ + void onAllDrop(); + } } diff --git a/xds/src/main/java/io/grpc/xds/LookasideLb.java b/xds/src/main/java/io/grpc/xds/LookasideLb.java index 3f24d7c77c4..52570284b30 100644 --- a/xds/src/main/java/io/grpc/xds/LookasideLb.java +++ b/xds/src/main/java/io/grpc/xds/LookasideLb.java @@ -30,7 +30,7 @@ import io.grpc.util.ForwardingLoadBalancer; import io.grpc.util.GracefulSwitchLoadBalancer; import io.grpc.xds.LocalityStore.LocalityStoreImpl; -import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.LookasideChannelLb.LookasideChannelCallback; import io.grpc.xds.XdsLoadBalancerProvider.XdsConfig; import java.util.Map; import java.util.logging.Logger; @@ -38,26 +38,26 @@ /** Lookaside load balancer that handles balancer name changes. */ final class LookasideLb extends ForwardingLoadBalancer { - private final AdsStreamCallback adsCallback; + private final LookasideChannelCallback lookasideChannelCallback; private final LookasideChannelLbFactory lookasideChannelLbFactory; private final GracefulSwitchLoadBalancer lookasideChannelLb; private final LoadBalancerRegistry lbRegistry; private String balancerName; - LookasideLb(Helper lookasideLbHelper, AdsStreamCallback adsCallback) { + LookasideLb(Helper lookasideLbHelper, LookasideChannelCallback lookasideChannelCallback) { this( - lookasideLbHelper, adsCallback, new LookasideChannelLbFactoryImpl(), + lookasideLbHelper, lookasideChannelCallback, new LookasideChannelLbFactoryImpl(), LoadBalancerRegistry.getDefaultRegistry()); } @VisibleForTesting LookasideLb( Helper lookasideLbHelper, - AdsStreamCallback adsCallback, + LookasideChannelCallback lookasideChannelCallback, LookasideChannelLbFactory lookasideChannelLbFactory, LoadBalancerRegistry lbRegistry) { - this.adsCallback = adsCallback; + this.lookasideChannelCallback = lookasideChannelCallback; this.lookasideChannelLbFactory = lookasideChannelLbFactory; this.lbRegistry = lbRegistry; this.lookasideChannelLb = new GracefulSwitchLoadBalancer(lookasideLbHelper); @@ -113,23 +113,25 @@ public String getPolicyName() { @Override public LoadBalancer newLoadBalancer(Helper helper) { - return lookasideChannelLbFactory.newLoadBalancer(helper, adsCallback, balancerName); + return lookasideChannelLbFactory.newLoadBalancer( + helper, lookasideChannelCallback, balancerName); } }; } @VisibleForTesting interface LookasideChannelLbFactory { - LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback, String balancerName); + LoadBalancer newLoadBalancer( + Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName); } private static final class LookasideChannelLbFactoryImpl implements LookasideChannelLbFactory { @Override - public LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback, - String balancerName) { + public LoadBalancer newLoadBalancer( + Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName) { return new LookasideChannelLb( - helper, adsCallback, initLbChannel(helper, balancerName), + helper, lookasideChannelCallback, initLbChannel(helper, balancerName), new LocalityStoreImpl(helper, LoadBalancerRegistry.getDefaultRegistry())); } diff --git a/xds/src/main/java/io/grpc/xds/XdsComms.java b/xds/src/main/java/io/grpc/xds/XdsComms.java deleted file mode 100644 index 57cf24e4cc4..00000000000 --- a/xds/src/main/java/io/grpc/xds/XdsComms.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; -import com.google.common.base.Stopwatch; -import com.google.common.base.Supplier; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Struct; -import com.google.protobuf.Value; -import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; -import io.envoyproxy.envoy.api.v2.DiscoveryRequest; -import io.envoyproxy.envoy.api.v2.DiscoveryResponse; -import io.envoyproxy.envoy.api.v2.core.Node; -import io.envoyproxy.envoy.api.v2.core.SocketAddress; -import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; -import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc; -import io.envoyproxy.envoy.type.FractionalPercent; -import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; -import io.grpc.ChannelLogger.ChannelLogLevel; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer.Helper; -import io.grpc.ManagedChannel; -import io.grpc.Status; -import io.grpc.SynchronizationContext.ScheduledHandle; -import io.grpc.internal.BackoffPolicy; -import io.grpc.stub.StreamObserver; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.TimeUnit; -import javax.annotation.CheckForNull; - -/** - * ADS client implementation. - */ -final class XdsComms { - private final ManagedChannel channel; - private final Helper helper; - private final BackoffPolicy.Provider backoffPolicyProvider; - private final Supplier stopwatchSupplier; - - @CheckForNull - private ScheduledHandle adsRpcRetryTimer; - - // never null - private BackoffPolicy adsRpcRetryPolicy; - // never null - private AdsStream adsStream; - - /** - * Information about the locality from EDS response. - */ - // TODO(zdapeng): move this class out. - static final class LocalityInfo { - final List eags; - final List endPointWeights; - final int localityWeight; - final int priority; - - LocalityInfo(Collection lbEndPoints, int localityWeight, int priority) { - List eags = new ArrayList<>(lbEndPoints.size()); - List endPointWeights = new ArrayList<>(lbEndPoints.size()); - for (LbEndpoint lbEndPoint : lbEndPoints) { - eags.add(lbEndPoint.eag); - endPointWeights.add(lbEndPoint.endPointWeight); - } - this.eags = Collections.unmodifiableList(eags); - this.endPointWeights = Collections.unmodifiableList(new ArrayList<>(endPointWeights)); - this.localityWeight = localityWeight; - this.priority = priority; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - LocalityInfo that = (LocalityInfo) o; - return localityWeight == that.localityWeight - && priority == that.priority - && Objects.equal(eags, that.eags) - && Objects.equal(endPointWeights, that.endPointWeights); - } - - @Override - public int hashCode() { - return Objects.hashCode(eags, endPointWeights, localityWeight, priority); - } - } - - static final class LbEndpoint { - final EquivalentAddressGroup eag; - final int endPointWeight; - - LbEndpoint(io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint lbEndpointProto) { - - this( - new EquivalentAddressGroup(ImmutableList.of(fromEnvoyProtoAddress(lbEndpointProto))), - lbEndpointProto.getLoadBalancingWeight().getValue()); - } - - @VisibleForTesting - LbEndpoint(EquivalentAddressGroup eag, int endPointWeight) { - this.eag = eag; - this.endPointWeight = endPointWeight; - } - - private static java.net.SocketAddress fromEnvoyProtoAddress( - io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint lbEndpointProto) { - SocketAddress socketAddress = lbEndpointProto.getEndpoint().getAddress().getSocketAddress(); - return new InetSocketAddress(socketAddress.getAddress(), socketAddress.getPortValue()); - } - } - - static final class DropOverload { - final String category; - final int dropsPerMillion; - - DropOverload(String category, int dropsPerMillion) { - this.category = category; - this.dropsPerMillion = dropsPerMillion; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DropOverload that = (DropOverload) o; - return dropsPerMillion == that.dropsPerMillion && Objects.equal(category, that.category); - } - - @Override - public int hashCode() { - return Objects.hashCode(category, dropsPerMillion); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("category", category) - .add("dropsPerMillion", dropsPerMillion) - .toString(); - } - } - - private final class AdsStream { - static final String EDS_TYPE_URL = - "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment"; - static final String TRAFFICDIRECTOR_GRPC_HOSTNAME = "TRAFFICDIRECTOR_GRPC_HOSTNAME"; - final LocalityStore localityStore; - - final AdsStreamCallback adsStreamCallback; - - final StreamObserver xdsRequestWriter; - - final Stopwatch retryStopwatch = stopwatchSupplier.get().start(); - - final StreamObserver xdsResponseReader = - new StreamObserver() { - - // Must be accessed in SynchronizationContext - boolean firstEdsResponseReceived; - - @Override - public void onNext(final DiscoveryResponse value) { - - class HandleResponseRunnable implements Runnable { - - @Override - public void run() { - String typeUrl = value.getTypeUrl(); - if (EDS_TYPE_URL.equals(typeUrl)) { - // Assuming standard mode. - - ClusterLoadAssignment clusterLoadAssignment; - try { - // maybe better to run this deserialization task out of syncContext? - clusterLoadAssignment = - value.getResources(0).unpack(ClusterLoadAssignment.class); - } catch (InvalidProtocolBufferException | RuntimeException e) { - cancelRpc("Received invalid EDS response", e); - adsStreamCallback.onError(); - scheduleRetry(); - return; - } - - helper.getChannelLogger().log( - ChannelLogLevel.DEBUG, - "Received an EDS response: {0}", clusterLoadAssignment); - if (!firstEdsResponseReceived) { - firstEdsResponseReceived = true; - adsStreamCallback.onWorking(); - } - - List dropOverloadsProto = - clusterLoadAssignment.getPolicy().getDropOverloadsList(); - ImmutableList.Builder dropOverloadsBuilder - = ImmutableList.builder(); - for (ClusterLoadAssignment.Policy.DropOverload dropOverload - : dropOverloadsProto) { - int rateInMillion = rateInMillion(dropOverload.getDropPercentage()); - dropOverloadsBuilder.add(new DropOverload( - dropOverload.getCategory(), rateInMillion)); - if (rateInMillion == 1000_000) { - adsStreamCallback.onAllDrop(); - break; - } - } - ImmutableList dropOverloads = dropOverloadsBuilder.build(); - localityStore.updateDropPercentage(dropOverloads); - - List localities = clusterLoadAssignment.getEndpointsList(); - ImmutableMap.Builder localityEndpointsMapping = - new ImmutableMap.Builder<>(); - for (LocalityLbEndpoints localityLbEndpoints : localities) { - io.envoyproxy.envoy.api.v2.core.Locality localityProto = - localityLbEndpoints.getLocality(); - XdsLocality locality = XdsLocality.fromLocalityProto(localityProto); - List lbEndPoints = new ArrayList<>(); - for (io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint lbEndpoint - : localityLbEndpoints.getLbEndpointsList()) { - lbEndPoints.add(new LbEndpoint(lbEndpoint)); - } - int localityWeight = localityLbEndpoints.getLoadBalancingWeight().getValue(); - int priority = localityLbEndpoints.getPriority(); - - if (localityWeight != 0) { - localityEndpointsMapping.put( - locality, new LocalityInfo(lbEndPoints, localityWeight, priority)); - } - } - - localityStore.updateLocalityStore(localityEndpointsMapping.build()); - } - } - } - - helper.getSynchronizationContext().execute(new HandleResponseRunnable()); - } - - @Override - public void onError(Throwable t) { - helper.getSynchronizationContext().execute( - new Runnable() { - @Override - public void run() { - closed = true; - if (cancelled) { - return; - } - adsStreamCallback.onError(); - scheduleRetry(); - } - }); - } - - @Override - public void onCompleted() { - onError(Status.INTERNAL.withDescription("Server closed the ADS streaming RPC") - .asException()); - } - - // run in SynchronizationContext - void scheduleRetry() { - if (channel.isShutdown()) { - return; - } - - checkState( - cancelled || closed, - "Scheduling retry while the stream is neither cancelled nor closed"); - - checkState( - adsRpcRetryTimer == null, "Scheduling retry while a retry is already pending"); - - class AdsRpcRetryTask implements Runnable { - @Override - public void run() { - adsRpcRetryTimer = null; - refreshAdsStream(); - } - } - - if (firstEdsResponseReceived) { - // Reset the backoff sequence if balancer has sent the initial response - adsRpcRetryPolicy = backoffPolicyProvider.get(); - // Retry immediately - helper.getSynchronizationContext().execute(new AdsRpcRetryTask()); - return; - } - - adsRpcRetryTimer = helper.getSynchronizationContext().schedule( - new AdsRpcRetryTask(), - adsRpcRetryPolicy.nextBackoffNanos() - retryStopwatch.elapsed(TimeUnit.NANOSECONDS), - TimeUnit.NANOSECONDS, - helper.getScheduledExecutorService()); - } - }; - - boolean cancelled; - boolean closed; - - AdsStream(AdsStreamCallback adsStreamCallback, LocalityStore localityStore) { - this.adsStreamCallback = adsStreamCallback; - this.xdsRequestWriter = AggregatedDiscoveryServiceGrpc.newStub(channel).withWaitForReady() - .streamAggregatedResources(xdsResponseReader); - this.localityStore = localityStore; - - checkState(adsRpcRetryTimer == null, "Creating AdsStream while retry is pending"); - // Assuming standard mode, and send EDS request only - DiscoveryRequest edsRequest = - DiscoveryRequest.newBuilder() - .setNode(Node.newBuilder() - .setMetadata(Struct.newBuilder() - .putFields( - "endpoints_required", - Value.newBuilder().setBoolValue(true).build()))) - .setTypeUrl(EDS_TYPE_URL) - // In the future, the right resource name can be obtained from CDS response. - .addResourceNames(helper.getAuthority()).build(); - helper.getChannelLogger().log(ChannelLogLevel.DEBUG, "Sending EDS request {0}", edsRequest); - xdsRequestWriter.onNext(edsRequest); - } - - AdsStream(AdsStream adsStream) { - this(adsStream.adsStreamCallback, adsStream.localityStore); - } - - // run in SynchronizationContext - void cancelRpc(String message, Throwable cause) { - if (cancelled) { - return; - } - cancelled = true; - xdsRequestWriter.onError( - Status.CANCELLED.withDescription(message).withCause(cause).asRuntimeException()); - } - } - - private static int rateInMillion(FractionalPercent fractionalPercent) { - int numerator = fractionalPercent.getNumerator(); - checkArgument(numerator >= 0, "numerator shouldn't be negative in %s", fractionalPercent); - - DenominatorType type = fractionalPercent.getDenominator(); - switch (type) { - case TEN_THOUSAND: - numerator *= 100; - break; - case HUNDRED: - numerator *= 100_00; - break; - case MILLION: - break; - default: - throw new IllegalArgumentException("unknown denominator type of " + fractionalPercent); - } - - if (numerator > 1000_000) { - numerator = 1000_000; - } - - return numerator; - } - - /** - * Starts a new ADS streaming RPC. - */ - XdsComms( - ManagedChannel channel, Helper helper, AdsStreamCallback adsStreamCallback, - LocalityStore localityStore, BackoffPolicy.Provider backoffPolicyProvider, - Supplier stopwatchSupplier) { - this.channel = checkNotNull(channel, "channel"); - this.helper = checkNotNull(helper, "helper"); - this.stopwatchSupplier = checkNotNull(stopwatchSupplier, "stopwatchSupplier"); - this.adsStream = new AdsStream( - checkNotNull(adsStreamCallback, "adsStreamCallback"), - checkNotNull(localityStore, "localityStore")); - this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); - this.adsRpcRetryPolicy = backoffPolicyProvider.get(); - } - - // run in SynchronizationContext - void refreshAdsStream() { - checkState(!channel.isShutdown(), "channel is alreday shutdown"); - - if (adsStream.closed || adsStream.cancelled) { - cancelRetryTimer(); - adsStream = new AdsStream(adsStream); - } - } - - // run in SynchronizationContext - // TODO: Change method name to shutdown or shutdownXdsComms if that gives better semantics ( - // cancel LB RPC and clean up retry timer). - void shutdownLbRpc(String message) { - adsStream.cancelRpc(message, null); - cancelRetryTimer(); - } - - // run in SynchronizationContext - private void cancelRetryTimer() { - if (adsRpcRetryTimer != null) { - adsRpcRetryTimer.cancel(); - adsRpcRetryTimer = null; - } - } - - /** - * Callback on ADS stream events. The callback methods should be called in a proper {@link - * io.grpc.SynchronizationContext}. - */ - interface AdsStreamCallback { - - /** - * Once the response observer receives the first response. - */ - void onWorking(); - - /** - * Once an error occurs in ADS stream. - */ - void onError(); - - /** - * Once receives a response indicating that 100% of calls should be dropped. - */ - void onAllDrop(); - } -} diff --git a/xds/src/main/java/io/grpc/xds/XdsComms2.java b/xds/src/main/java/io/grpc/xds/XdsComms2.java index cbe5512e10c..5ad18a3b908 100644 --- a/xds/src/main/java/io/grpc/xds/XdsComms2.java +++ b/xds/src/main/java/io/grpc/xds/XdsComms2.java @@ -36,7 +36,6 @@ import io.grpc.SynchronizationContext.ScheduledHandle; import io.grpc.internal.BackoffPolicy; import io.grpc.stub.StreamObserver; -import io.grpc.xds.LookasideChannelLb.AdsStreamCallback2; import java.util.concurrent.TimeUnit; import javax.annotation.CheckForNull; @@ -63,7 +62,7 @@ private final class AdsStream { static final String EDS_TYPE_URL = "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment"; - final AdsStreamCallback2 adsStreamCallback2; + final AdsStreamCallback adsStreamCallback; final StreamObserver xdsRequestWriter; final Stopwatch retryStopwatch = stopwatchSupplier.get().start(); @@ -90,7 +89,7 @@ public void run() { value.getResources(0).unpack(ClusterLoadAssignment.class); } catch (InvalidProtocolBufferException | RuntimeException e) { cancelRpc("Received invalid EDS response", e); - adsStreamCallback2.onError(); + adsStreamCallback.onError(); scheduleRetry(); return; } @@ -98,7 +97,8 @@ public void run() { helper.getChannelLogger().log( ChannelLogLevel.DEBUG, "Received an EDS response: {0}", clusterLoadAssignment); - adsStreamCallback2.onEdsResponse(clusterLoadAssignment); + firstEdsResponseReceived = true; + adsStreamCallback.onEdsResponse(clusterLoadAssignment); } } } @@ -116,7 +116,7 @@ public void run() { if (cancelled) { return; } - adsStreamCallback2.onError(); + adsStreamCallback.onError(); scheduleRetry(); } }); @@ -168,8 +168,8 @@ public void run() { boolean cancelled; boolean closed; - AdsStream(AdsStreamCallback2 adsStreamCallback2) { - this.adsStreamCallback2 = adsStreamCallback2; + AdsStream(AdsStreamCallback adsStreamCallback) { + this.adsStreamCallback = adsStreamCallback; this.xdsRequestWriter = AggregatedDiscoveryServiceGrpc.newStub(channel).withWaitForReady() .streamAggregatedResources(xdsResponseReader); @@ -190,7 +190,7 @@ public void run() { } AdsStream(AdsStream adsStream) { - this(adsStream.adsStreamCallback2); + this(adsStream.adsStreamCallback); } // run in SynchronizationContext @@ -208,13 +208,13 @@ void cancelRpc(String message, Throwable cause) { * Starts a new ADS streaming RPC. */ XdsComms2( - ManagedChannel channel, Helper helper, AdsStreamCallback2 adsStreamCallback2, + ManagedChannel channel, Helper helper, AdsStreamCallback adsStreamCallback, BackoffPolicy.Provider backoffPolicyProvider, Supplier stopwatchSupplier) { this.channel = checkNotNull(channel, "channel"); this.helper = checkNotNull(helper, "helper"); this.stopwatchSupplier = checkNotNull(stopwatchSupplier, "stopwatchSupplier"); this.adsStream = new AdsStream( - checkNotNull(adsStreamCallback2, "adsStreamCallback2")); + checkNotNull(adsStreamCallback, "adsStreamCallback")); this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); this.adsRpcRetryPolicy = backoffPolicyProvider.get(); } @@ -244,4 +244,14 @@ private void cancelRetryTimer() { adsRpcRetryTimer = null; } } + + /** + * Callback on ADS stream events. The callback methods should be called in a proper {@link + * io.grpc.SynchronizationContext}. + */ + interface AdsStreamCallback { + void onEdsResponse(ClusterLoadAssignment clusterLoadAssignment); + + void onError(); + } } diff --git a/xds/src/main/java/io/grpc/xds/XdsLbState.java b/xds/src/main/java/io/grpc/xds/XdsLbState.java deleted file mode 100644 index a2c9157a850..00000000000 --- a/xds/src/main/java/io/grpc/xds/XdsLbState.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.grpc.Attributes; -import io.grpc.ConnectivityStateInfo; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer.Helper; -import io.grpc.LoadBalancer.Subchannel; -import io.grpc.ManagedChannel; -import io.grpc.Status; -import io.grpc.internal.BackoffPolicy; -import io.grpc.internal.GrpcUtil; -import io.grpc.internal.ServiceConfigUtil.LbConfig; -import io.grpc.xds.XdsComms.AdsStreamCallback; -import java.util.List; -import javax.annotation.Nullable; - -/** - * The states of an XDS working session of {@link XdsLoadBalancer}. Created when XdsLoadBalancer - * switches to the current mode. Shutdown and discarded when XdsLoadBalancer switches to another - * mode. - * - *

    There might be two implementations: - * - *

      - *
    • Standard plugin: No child plugin specified in lb config. Lb will send CDS request, - * and then EDS requests. EDS requests request for endpoints.
    • - *
    • Custom plugin: Child plugin specified in lb config. Lb will send EDS directly. EDS requests - * do not request for endpoints.
    • - *
    - */ -class XdsLbState { - - final String balancerName; - - @Nullable - final LbConfig childPolicy; - - private final LocalityStore localityStore; - private final Helper helper; - private final ManagedChannel channel; - private final AdsStreamCallback adsStreamCallback; - private final BackoffPolicy.Provider backoffPolicyProvider; - - @Nullable - private XdsComms xdsComms; - - XdsLbState( - String balancerName, - @Nullable LbConfig childPolicy, - Helper helper, - LocalityStore localityStore, - ManagedChannel channel, - AdsStreamCallback adsStreamCallback, - BackoffPolicy.Provider backoffPolicyProvider) { - this.balancerName = checkNotNull(balancerName, "balancerName"); - this.childPolicy = childPolicy; - this.helper = checkNotNull(helper, "helper"); - this.localityStore = checkNotNull(localityStore, "localityStore"); - this.channel = checkNotNull(channel, "channel"); - this.adsStreamCallback = checkNotNull(adsStreamCallback, "adsStreamCallback"); - this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); - } - - final void handleResolvedAddressGroups( - List servers, Attributes attributes) { - - // start XdsComms if not already alive - if (xdsComms != null) { - xdsComms.refreshAdsStream(); - } else { - // TODO(zdapeng): pass a helper that has the right ChannelLogger for the oobChannel - xdsComms = new XdsComms( - channel, helper, adsStreamCallback, localityStore, backoffPolicyProvider, - GrpcUtil.STOPWATCH_SUPPLIER); - } - - // TODO: maybe update picker - } - - final void handleNameResolutionError(Status error) { - // NO-OP? - } - - final void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo newState) { - // TODO: maybe update picker - localityStore.handleSubchannelState(subchannel, newState); - } - - ManagedChannel shutdownAndReleaseChannel(String message) { - localityStore.reset(); - if (xdsComms != null) { - xdsComms.shutdownLbRpc(message); - xdsComms = null; - } - return channel; - } -} diff --git a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer.java b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer.java deleted file mode 100644 index 22a19a5b32f..00000000000 --- a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer.java +++ /dev/null @@ -1,479 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; -import static io.grpc.ConnectivityState.READY; -import static io.grpc.ConnectivityState.TRANSIENT_FAILURE; -import static io.grpc.xds.XdsLoadBalancerProvider.XDS_POLICY_NAME; -import static java.util.logging.Level.FINEST; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Objects; -import com.google.common.collect.ImmutableList; -import io.grpc.Attributes; -import io.grpc.ChannelLogger.ChannelLogLevel; -import io.grpc.ConnectivityState; -import io.grpc.ConnectivityStateInfo; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer; -import io.grpc.LoadBalancerRegistry; -import io.grpc.ManagedChannel; -import io.grpc.ManagedChannelBuilder; -import io.grpc.NameResolver.ConfigOrError; -import io.grpc.Status; -import io.grpc.SynchronizationContext.ScheduledHandle; -import io.grpc.internal.BackoffPolicy; -import io.grpc.internal.GrpcAttributes; -import io.grpc.internal.ServiceConfigUtil.LbConfig; -import io.grpc.util.ForwardingLoadBalancerHelper; -import io.grpc.xds.LoadReportClient.LoadReportCallback; -import io.grpc.xds.LoadReportClientImpl.LoadReportClientFactory; -import io.grpc.xds.LocalityStore.LocalityStoreImpl; -import io.grpc.xds.XdsComms.AdsStreamCallback; -import io.grpc.xds.XdsLoadBalancerProvider.XdsConfig; -import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; -import javax.annotation.CheckForNull; -import javax.annotation.Nullable; - -/** - * A {@link LoadBalancer} that uses the XDS protocol. - */ -final class XdsLoadBalancer extends LoadBalancer { - - private final LocalityStore localityStore; - private final Helper helper; - private final LoadBalancerRegistry lbRegistry; - private final FallbackManager fallbackManager; - private final BackoffPolicy.Provider backoffPolicyProvider; - private final LoadReportClientFactory lrsClientFactory; - - @Nullable - private LoadReportClient lrsClient; - @Nullable - private XdsLbState xdsLbState; - private final AdsStreamCallback adsStreamCallback = new AdsStreamCallback() { - - @Override - public void onWorking() { - if (fallbackManager.childPolicyHasBeenReady) { - // cancel Fallback-After-Startup timer if there's any - fallbackManager.cancelFallbackTimer(); - } - - fallbackManager.childBalancerWorked = true; - lrsClient.startLoadReporting(lrsCallback); - } - - @Override - public void onError() { - if (!fallbackManager.childBalancerWorked) { - // start Fallback-at-Startup immediately - fallbackManager.useFallbackPolicy(); - } else if (fallbackManager.childPolicyHasBeenReady) { - // TODO: schedule a timer for Fallback-After-Startup - } // else: the Fallback-at-Startup timer is still pending, noop and wait - } - - @Override - public void onAllDrop() { - fallbackManager.cancelFallback(); - } - }; - - private final LoadReportCallback lrsCallback = - new LoadReportCallback() { - - @Override - public void onReportResponse(long reportIntervalNano) { - localityStore.updateOobMetricsReportInterval(reportIntervalNano); - } - }; - - private LbConfig fallbackPolicy; - - XdsLoadBalancer(Helper helper, LoadBalancerRegistry lbRegistry, - BackoffPolicy.Provider backoffPolicyProvider) { - this(helper, lbRegistry, backoffPolicyProvider, LoadReportClientFactory.getInstance(), - new FallbackManager(helper, lbRegistry)); - } - - private XdsLoadBalancer(Helper helper, - LoadBalancerRegistry lbRegistry, - BackoffPolicy.Provider backoffPolicyProvider, - LoadReportClientFactory lrsClientFactory, - FallbackManager fallbackManager) { - this(helper, lbRegistry, backoffPolicyProvider, lrsClientFactory, fallbackManager, - new LocalityStoreImpl(new LocalityStoreHelper(helper, fallbackManager), lbRegistry)); - } - - @VisibleForTesting - XdsLoadBalancer(Helper helper, - LoadBalancerRegistry lbRegistry, - BackoffPolicy.Provider backoffPolicyProvider, - LoadReportClientFactory lrsClientFactory, - FallbackManager fallbackManager, - LocalityStore localityStore) { - this.helper = checkNotNull(helper, "helper"); - this.lbRegistry = checkNotNull(lbRegistry, "lbRegistry"); - this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); - this.lrsClientFactory = checkNotNull(lrsClientFactory, "lrsClientFactory"); - this.fallbackManager = checkNotNull(fallbackManager, "fallbackManager"); - this.localityStore = checkNotNull(localityStore, "localityStore"); - } - - private static final class LocalityStoreHelper extends ForwardingLoadBalancerHelper { - - final Helper delegate; - final FallbackManager fallbackManager; - - LocalityStoreHelper(Helper delegate, FallbackManager fallbackManager) { - this.delegate = checkNotNull(delegate, "delegate"); - this.fallbackManager = checkNotNull(fallbackManager, "fallbackManager"); - } - - @Override - protected Helper delegate() { - return delegate; - } - - @Override - public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { - - if (newState == READY) { - checkState( - fallbackManager.childBalancerWorked, - "channel goes to READY before the load balancer even worked"); - fallbackManager.childPolicyHasBeenReady = true; - fallbackManager.cancelFallback(); - } - - if (!fallbackManager.isInFallbackMode()) { - delegate.getChannelLogger().log( - ChannelLogLevel.INFO, "Picker updated - state: {0}, picker: {1}", newState, newPicker); - delegate.updateBalancingState(newState, newPicker); - } - } - } - - @Override - public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { - List servers = resolvedAddresses.getAddresses(); - Attributes attributes = resolvedAddresses.getAttributes(); - Map newRawLbConfig = checkNotNull( - attributes.get(ATTR_LOAD_BALANCING_CONFIG), "ATTR_LOAD_BALANCING_CONFIG not available"); - - ConfigOrError cfg = - XdsLoadBalancerProvider.parseLoadBalancingConfigPolicy(newRawLbConfig, lbRegistry); - if (cfg.getError() != null) { - throw cfg.getError().asRuntimeException(); - } - XdsConfig xdsConfig = (XdsConfig) cfg.getConfig(); - fallbackPolicy = xdsConfig.fallbackPolicy; - fallbackManager.updateFallbackServers(servers, attributes, fallbackPolicy); - fallbackManager.startFallbackTimer(); - handleNewConfig(xdsConfig); - xdsLbState.handleResolvedAddressGroups(servers, attributes); - } - - private void handleNewConfig(XdsConfig xdsConfig) { - String newBalancerName = xdsConfig.balancerName; - LbConfig childPolicy = xdsConfig.childPolicy; - ManagedChannel lbChannel; - if (xdsLbState == null) { - lbChannel = initLbChannel(helper, newBalancerName); - lrsClient = - lrsClientFactory.createLoadReportClient(lbChannel, helper, backoffPolicyProvider, - localityStore.getLoadStatsStore()); - } else if (!newBalancerName.equals(xdsLbState.balancerName)) { - lrsClient.stopLoadReporting(); - ManagedChannel oldChannel = - xdsLbState.shutdownAndReleaseChannel( - String.format("Changing balancer name from %s to %s", xdsLbState.balancerName, - newBalancerName)); - oldChannel.shutdown(); - lbChannel = initLbChannel(helper, newBalancerName); - lrsClient = - lrsClientFactory.createLoadReportClient(lbChannel, helper, backoffPolicyProvider, - localityStore.getLoadStatsStore()); - } else if (!Objects.equal( - getPolicyNameOrNull(childPolicy), - getPolicyNameOrNull(xdsLbState.childPolicy))) { - // Changing child policy does not affect load reporting. - lbChannel = - xdsLbState.shutdownAndReleaseChannel( - String.format("Changing child policy from %s to %s", xdsLbState.childPolicy, - childPolicy)); - } else { // effectively no change in policy, keep xdsLbState unchanged - return; - } - xdsLbState = - new XdsLbState(newBalancerName, childPolicy, helper, localityStore, lbChannel, - adsStreamCallback, backoffPolicyProvider); - } - - private static ManagedChannel initLbChannel(Helper helper, String balancerName) { - ManagedChannel channel; - try { - channel = helper.createResolvingOobChannel(balancerName); - } catch (UnsupportedOperationException uoe) { - // Temporary solution until createResolvingOobChannel is implemented - // FIXME (https://github.com/grpc/grpc-java/issues/5495) - Logger logger = Logger.getLogger(XdsLoadBalancer.class.getName()); - if (logger.isLoggable(FINEST)) { - logger.log( - FINEST, - "createResolvingOobChannel() not supported by the helper: " + helper, - uoe); - logger.log( - FINEST, - "creating oob channel for target {0} using default ManagedChannelBuilder", - balancerName); - } - channel = ManagedChannelBuilder.forTarget(balancerName).build(); - } - return channel; - } - - @Nullable - private static String getPolicyNameOrNull(@Nullable LbConfig config) { - if (config == null) { - return null; - } - return config.getPolicyName(); - } - - @Override - public void handleNameResolutionError(Status error) { - if (xdsLbState != null) { - xdsLbState.handleNameResolutionError(error); - } - if (fallbackManager.isInFallbackMode()) { - fallbackManager.fallbackBalancer.handleNameResolutionError(error); - } - if (xdsLbState == null && !fallbackManager.isInFallbackMode()) { - helper.updateBalancingState(TRANSIENT_FAILURE, new ErrorPicker(error)); - } - } - - /** - * This is only for the subchannel that is created by the child/fallback balancer using the - * old API {@link LoadBalancer.Helper#createSubchannel(EquivalentAddressGroup, Attributes)} or - * {@link LoadBalancer.Helper#createSubchannel(List, Attributes)}. Otherwise, it either won't be - * called or won't have any effect. - */ - @Deprecated - @Override - public void handleSubchannelState(Subchannel subchannel, ConnectivityStateInfo newState) { - if (fallbackManager.isInFallbackMode()) { - fallbackManager.fallbackBalancer.handleSubchannelState(subchannel, newState); - } - - // xdsLbState should never be null here since handleSubchannelState cannot be called while the - // lb is shutdown. - xdsLbState.handleSubchannelState(subchannel, newState); - } - - @Override - public void shutdown() { - if (xdsLbState != null) { - lrsClient.stopLoadReporting(); - lrsClient = null; - ManagedChannel channel = xdsLbState.shutdownAndReleaseChannel("Client shutdown"); - channel.shutdown(); - xdsLbState = null; - } - fallbackManager.cancelFallback(); - } - - @Override - public boolean canHandleEmptyAddressListFromNameResolution() { - return true; - } - - @Nullable - XdsLbState getXdsLbStateForTest() { - return xdsLbState; - } - - @VisibleForTesting - static final class FallbackManager { - - private static final long FALLBACK_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); // same as grpclb - - private final Helper helper; - private final LoadBalancerRegistry lbRegistry; - - private LbConfig fallbackPolicy; - - // read-only for outer class - private LoadBalancer fallbackBalancer; - - // Scheduled only once. Never reset. - @CheckForNull - private ScheduledHandle fallbackTimer; - - private List fallbackServers = ImmutableList.of(); - private Attributes fallbackAttributes; - - // allow value write by outer class - private boolean childBalancerWorked; - private boolean childPolicyHasBeenReady; - - FallbackManager(Helper helper, LoadBalancerRegistry lbRegistry) { - this.helper = checkNotNull(helper, "helper"); - this.lbRegistry = checkNotNull(lbRegistry, "lbRegistry"); - } - - /** - * Fallback mode being on indicates that an update from child LBs will be ignored unless the - * update triggers turning off the fallback mode first. - */ - boolean isInFallbackMode() { - return fallbackBalancer != null; - } - - void cancelFallbackTimer() { - if (fallbackTimer != null) { - fallbackTimer.cancel(); - } - } - - void cancelFallback() { - cancelFallbackTimer(); - if (fallbackBalancer != null) { - helper.getChannelLogger().log( - ChannelLogLevel.INFO, "Shutting down XDS fallback balancer"); - fallbackBalancer.shutdown(); - fallbackBalancer = null; - } - } - - void useFallbackPolicy() { - if (fallbackBalancer != null) { - return; - } - - cancelFallbackTimer(); - - helper.getChannelLogger().log( - ChannelLogLevel.INFO, "Using XDS fallback policy"); - - final class FallbackBalancerHelper extends ForwardingLoadBalancerHelper { - LoadBalancer balancer; - - @Override - public void updateBalancingState(ConnectivityState newState, SubchannelPicker newPicker) { - checkNotNull(balancer, "there is a bug"); - if (balancer != fallbackBalancer) { - // ignore updates from a misbehaving shutdown fallback balancer - return; - } - helper.getChannelLogger().log( - ChannelLogLevel.INFO, - "Picker updated - state: {0}, picker: {1}", newState, newPicker); - super.updateBalancingState(newState, newPicker); - } - - @Override - protected Helper delegate() { - return helper; - } - } - - FallbackBalancerHelper fallbackBalancerHelper = new FallbackBalancerHelper(); - fallbackBalancer = lbRegistry.getProvider(fallbackPolicy.getPolicyName()) - .newLoadBalancer(fallbackBalancerHelper); - fallbackBalancerHelper.balancer = fallbackBalancer; - propagateFallbackAddresses(); - } - - void updateFallbackServers( - List servers, Attributes attributes, - LbConfig fallbackPolicy) { - this.fallbackServers = servers; - this.fallbackAttributes = Attributes.newBuilder() - .setAll(attributes) - .set(ATTR_LOAD_BALANCING_CONFIG, fallbackPolicy.getRawConfigValue()) - .build(); - LbConfig currentFallbackPolicy = this.fallbackPolicy; - this.fallbackPolicy = fallbackPolicy; - if (fallbackBalancer != null) { - if (fallbackPolicy.getPolicyName().equals(currentFallbackPolicy.getPolicyName())) { - propagateFallbackAddresses(); - } else { - fallbackBalancer.shutdown(); - fallbackBalancer = null; - useFallbackPolicy(); - } - } - } - - private void propagateFallbackAddresses() { - String fallbackPolicyName = fallbackPolicy.getPolicyName(); - List servers = fallbackServers; - - // Some addresses in the list may be grpclb-v1 balancer addresses, so if the fallback policy - // does not support grpclb-v1 balancer addresses, then we need to exclude them from the list. - if (!fallbackPolicyName.equals("grpclb") && !fallbackPolicyName.equals(XDS_POLICY_NAME)) { - ImmutableList.Builder backends = ImmutableList.builder(); - for (EquivalentAddressGroup eag : fallbackServers) { - if (eag.getAttributes().get(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY) == null) { - backends.add(eag); - } - } - servers = backends.build(); - } - - // TODO(zhangkun83): FIXME(#5496): this is a temporary hack. - if (servers.isEmpty() - && !fallbackBalancer.canHandleEmptyAddressListFromNameResolution()) { - fallbackBalancer.handleNameResolutionError(Status.UNAVAILABLE.withDescription( - "NameResolver returned no usable address." - + " addrs=" + fallbackServers + ", attrs=" + fallbackAttributes)); - } else { - // TODO(carl-mastrangelo): propagate the load balancing config policy - fallbackBalancer.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(servers) - .setAttributes(fallbackAttributes) - .build()); - } - } - - void startFallbackTimer() { - if (fallbackTimer == null) { - class FallbackTask implements Runnable { - @Override - public void run() { - useFallbackPolicy(); - } - } - - fallbackTimer = helper.getSynchronizationContext().schedule( - new FallbackTask(), FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS, - helper.getScheduledExecutorService()); - } - } - } - -} diff --git a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java index 64bd635afdb..a68b31354d3 100644 --- a/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java +++ b/xds/src/main/java/io/grpc/xds/XdsLoadBalancer2.java @@ -27,7 +27,7 @@ import io.grpc.Status; import io.grpc.SynchronizationContext.ScheduledHandle; import io.grpc.util.ForwardingLoadBalancerHelper; -import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.LookasideChannelLb.LookasideChannelCallback; import java.util.concurrent.TimeUnit; import javax.annotation.CheckForNull; import javax.annotation.Nullable; @@ -46,7 +46,7 @@ final class XdsLoadBalancer2 extends LoadBalancer { private final Helper helper; private final LoadBalancer lookasideLb; private final LoadBalancer.Factory fallbackLbFactory; - private final AdsStreamCallback adsCallback = new AdsStreamCallback() { + private final LookasideChannelCallback lookasideChannelCallback = new LookasideChannelCallback() { @Override public void onWorking() { if (childPolicyHasBeenReady) { @@ -93,7 +93,8 @@ public void onAllDrop() { LookasideLbFactory lookasideLbFactory, LoadBalancer.Factory fallbackLbFactory) { this.helper = helper; - this.lookasideLb = lookasideLbFactory.newLoadBalancer(new LookasideLbHelper(), adsCallback); + this.lookasideLb = lookasideLbFactory.newLoadBalancer(new LookasideLbHelper(), + lookasideChannelCallback); this.fallbackLbFactory = fallbackLbFactory; } @@ -246,13 +247,14 @@ public void updateBalancingState(ConnectivityState newState, SubchannelPicker ne /** Factory of a look-aside load balancer. The interface itself is for convenience in test. */ @VisibleForTesting interface LookasideLbFactory { - LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback); + LoadBalancer newLoadBalancer(Helper helper, LookasideChannelCallback lookasideChannelCallback); } private static final class LookasideLbFactoryImpl implements LookasideLbFactory { @Override - public LoadBalancer newLoadBalancer(Helper lookasideLbHelper, AdsStreamCallback adsCallback) { - return new LookasideLb(lookasideLbHelper, adsCallback); + public LoadBalancer newLoadBalancer( + Helper lookasideLbHelper, LookasideChannelCallback lookasideChannelCallback) { + return new LookasideLb(lookasideLbHelper, lookasideChannelCallback); } } diff --git a/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java index 8e311f6384f..7d1316cdec2 100644 --- a/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java @@ -29,7 +29,6 @@ import io.grpc.LoadBalancerRegistry; import io.grpc.NameResolver.ConfigOrError; import io.grpc.Status; -import io.grpc.internal.ExponentialBackoffPolicy; import io.grpc.internal.ServiceConfigUtil; import io.grpc.internal.ServiceConfigUtil.LbConfig; import java.util.List; @@ -66,8 +65,7 @@ public String getPolicyName() { @Override public LoadBalancer newLoadBalancer(Helper helper) { - return new XdsLoadBalancer(helper, LoadBalancerRegistry.getDefaultRegistry(), - new ExponentialBackoffPolicy.Provider()); + return new XdsLoadBalancer2(helper); } @Override diff --git a/xds/src/main/java/io/grpc/xds/XdsLocality.java b/xds/src/main/java/io/grpc/xds/XdsLocality.java deleted file mode 100644 index 5b426919153..00000000000 --- a/xds/src/main/java/io/grpc/xds/XdsLocality.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.MoreObjects; -import com.google.common.base.Objects; - -/** - * An {@code XdsLocality} object is simply a POJO representation for {@link - * io.envoyproxy.envoy.api.v2.core.Locality}, with only details needed for {@link XdsLoadBalancer}. - */ -final class XdsLocality { - private final String region; - private final String zone; - private final String subzone; - - /** Must only be used for testing. */ - @VisibleForTesting - XdsLocality(String region, String zone, String subzone) { - this.region = region; - this.zone = zone; - this.subzone = subzone; - } - - static XdsLocality fromLocalityProto(io.envoyproxy.envoy.api.v2.core.Locality locality) { - return new XdsLocality( - /* region = */ locality.getRegion(), - /* zone = */ locality.getZone(), - /* subzone = */ locality.getSubZone()); - } - - io.envoyproxy.envoy.api.v2.core.Locality toLocalityProto() { - return io.envoyproxy.envoy.api.v2.core.Locality.newBuilder() - .setRegion(region) - .setZone(zone) - .setSubZone(subzone) - .build(); - } - - String getRegion() { - return region; - } - - String getZone() { - return zone; - } - - String getSubzone() { - return subzone; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - XdsLocality locality = (XdsLocality) o; - return Objects.equal(region, locality.region) - && Objects.equal(zone, locality.zone) - && Objects.equal(subzone, locality.subzone); - } - - @Override - public int hashCode() { - return Objects.hashCode(region, zone, subzone); - } - - @Override - public String toString() { - return MoreObjects.toStringHelper(this) - .add("region", region) - .add("zone", zone) - .add("subzone", subzone) - .toString(); - } -} diff --git a/xds/src/test/java/io/grpc/xds/XdsLocalityTest.java b/xds/src/test/java/io/grpc/xds/ClusterLoadAssignmentDataTest.java similarity index 88% rename from xds/src/test/java/io/grpc/xds/XdsLocalityTest.java rename to xds/src/test/java/io/grpc/xds/ClusterLoadAssignmentDataTest.java index 8c3f9654525..8293790b20e 100644 --- a/xds/src/test/java/io/grpc/xds/XdsLocalityTest.java +++ b/xds/src/test/java/io/grpc/xds/ClusterLoadAssignmentDataTest.java @@ -20,18 +20,19 @@ import com.google.common.testing.EqualsTester; import io.envoyproxy.envoy.api.v2.core.Locality; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; /** - * Unit tests for {@link XdsLocality}. + * Unit tests for {@link ClusterLoadAssignmentData}. */ @RunWith(JUnit4.class) -public class XdsLocalityTest { +public class ClusterLoadAssignmentDataTest { @Test - public void convertToAndFromLocalityProto() { + public void xdsLocality_convertToAndFromLocalityProto() { Locality locality = Locality.newBuilder() .setRegion("test_region") @@ -50,7 +51,7 @@ public void convertToAndFromLocalityProto() { } @Test - public void equal() { + public void xdsLocality_equal() { new EqualsTester() .addEqualityGroup( new XdsLocality("region-a", "zone-a", "subzone-a"), @@ -65,7 +66,7 @@ public void equal() { } @Test - public void hash() { + public void xdsLocality_hash() { assertThat(new XdsLocality("region", "zone", "subzone").hashCode()) .isEqualTo(new XdsLocality("region", "zone","subzone").hashCode()); } diff --git a/xds/src/test/java/io/grpc/xds/FallbackManagerTest.java b/xds/src/test/java/io/grpc/xds/FallbackManagerTest.java deleted file mode 100644 index a79a5dd9082..00000000000 --- a/xds/src/test/java/io/grpc/xds/FallbackManagerTest.java +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.ImmutableList; -import io.grpc.Attributes; -import io.grpc.ChannelLogger; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer; -import io.grpc.LoadBalancer.Helper; -import io.grpc.LoadBalancer.ResolvedAddresses; -import io.grpc.LoadBalancerProvider; -import io.grpc.LoadBalancerRegistry; -import io.grpc.Status; -import io.grpc.Status.Code; -import io.grpc.SynchronizationContext; -import io.grpc.internal.FakeClock; -import io.grpc.internal.GrpcAttributes; -import io.grpc.internal.ServiceConfigUtil.LbConfig; -import io.grpc.xds.XdsLoadBalancer.FallbackManager; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.HashMap; -import java.util.List; -import java.util.concurrent.TimeUnit; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Unit test for {@link FallbackManager}. - */ -@RunWith(JUnit4.class) -public class FallbackManagerTest { - - private static final long FALLBACK_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); - - private final FakeClock fakeClock = new FakeClock(); - private final LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry(); - - private final LoadBalancerProvider fakeFallbackLbProvider = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return fallbackPolicy.getPolicyName(); - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - return fakeFallbackLb; - } - }; - - private final LoadBalancerProvider fakeRoundRonbinLbProvider = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return "round_robin"; - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - return fakeRoundRobinLb; - } - }; - - private final SynchronizationContext syncContext = new SynchronizationContext( - new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - throw new AssertionError(e); - } - }); - - @Mock - private Helper helper; - @Mock - private LoadBalancer fakeRoundRobinLb; - @Mock - private LoadBalancer fakeFallbackLb; - @Mock - private ChannelLogger channelLogger; - - private FallbackManager fallbackManager; - private LbConfig fallbackPolicy; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - doReturn(syncContext).when(helper).getSynchronizationContext(); - doReturn(fakeClock.getScheduledExecutorService()).when(helper).getScheduledExecutorService(); - doReturn(channelLogger).when(helper).getChannelLogger(); - fallbackPolicy = new LbConfig("test_policy", new HashMap()); - lbRegistry.register(fakeRoundRonbinLbProvider); - lbRegistry.register(fakeFallbackLbProvider); - fallbackManager = new FallbackManager(helper, lbRegistry); - } - - @After - public void tearDown() { - assertThat(fakeClock.getPendingTasks()).isEmpty(); - } - - @Test - public void useFallbackWhenTimeout() { - fallbackManager.startFallbackTimer(); - List eags = ImmutableList.of( - new EquivalentAddressGroup(ImmutableList.of(new InetSocketAddress(8080)))); - fallbackManager.updateFallbackServers( - eags, Attributes.EMPTY, fallbackPolicy); - - assertThat(fallbackManager.isInFallbackMode()).isFalse(); - verify(fakeFallbackLb, never()) - .handleResolvedAddresses(ArgumentMatchers.any(ResolvedAddresses.class)); - - fakeClock.forwardTime(FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); - - assertThat(fallbackManager.isInFallbackMode()).isTrue(); - verify(fakeFallbackLb).handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(eags) - .setAttributes( - Attributes.newBuilder() - .set( - LoadBalancer.ATTR_LOAD_BALANCING_CONFIG, - fallbackPolicy.getRawConfigValue()) - .build()) - .build()); - } - - @Test - public void fallback_handleBackendsEagsOnly() { - fallbackManager.startFallbackTimer(); - EquivalentAddressGroup eag0 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8080))); - Attributes attributes = Attributes - .newBuilder() - .set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "this is a balancer address") - .build(); - EquivalentAddressGroup eag1 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8081)), attributes); - EquivalentAddressGroup eag2 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8082))); - List eags = ImmutableList.of(eag0, eag1, eag2); - fallbackManager.updateFallbackServers( - eags, Attributes.EMPTY, fallbackPolicy); - - fakeClock.forwardTime(FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); - - assertThat(fallbackManager.isInFallbackMode()).isTrue(); - verify(fakeFallbackLb).handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(ImmutableList.of(eag0, eag2)) - .setAttributes( - Attributes.newBuilder() - .set( - LoadBalancer.ATTR_LOAD_BALANCING_CONFIG, - fallbackPolicy.getRawConfigValue()) - .build()) - .build()); - } - - @Test - public void fallback_handleGrpclbAddresses() { - lbRegistry.deregister(fakeFallbackLbProvider); - fallbackPolicy = new LbConfig("grpclb", new HashMap()); - lbRegistry.register(fakeFallbackLbProvider); - - fallbackManager.startFallbackTimer(); - EquivalentAddressGroup eag0 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8080))); - Attributes attributes = Attributes - .newBuilder() - .set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "this is a balancer address") - .build(); - EquivalentAddressGroup eag1 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8081)), attributes); - EquivalentAddressGroup eag2 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8082))); - List eags = ImmutableList.of(eag0, eag1, eag2); - fallbackManager.updateFallbackServers( - eags, Attributes.EMPTY, fallbackPolicy); - - fakeClock.forwardTime(FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); - - assertThat(fallbackManager.isInFallbackMode()).isTrue(); - verify(fakeFallbackLb).handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(eags) - .setAttributes( - Attributes.newBuilder() - .set( - LoadBalancer.ATTR_LOAD_BALANCING_CONFIG, - fallbackPolicy.getRawConfigValue()) - .build()) - .build()); - } - - @Test - public void fallback_onlyGrpclbAddresses_NoBackendAddress() { - lbRegistry.deregister(fakeFallbackLbProvider); - fallbackPolicy = new LbConfig("not_grpclb", new HashMap()); - lbRegistry.register(fakeFallbackLbProvider); - - fallbackManager.startFallbackTimer(); - Attributes attributes = Attributes - .newBuilder() - .set(GrpcAttributes.ATTR_LB_ADDR_AUTHORITY, "this is a balancer address") - .build(); - EquivalentAddressGroup eag1 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8081)), attributes); - EquivalentAddressGroup eag2 = new EquivalentAddressGroup( - ImmutableList.of(new InetSocketAddress(8082)), attributes); - List eags = ImmutableList.of(eag1, eag2); - fallbackManager.updateFallbackServers( - eags, Attributes.EMPTY, fallbackPolicy); - - fakeClock.forwardTime(FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); - - assertThat(fallbackManager.isInFallbackMode()).isTrue(); - ArgumentCaptor statusCaptor = ArgumentCaptor.forClass(Status.class); - verify(fakeFallbackLb).handleNameResolutionError(statusCaptor.capture()); - assertThat(statusCaptor.getValue().getCode()).isEqualTo(Code.UNAVAILABLE); - } - - @Test - public void cancelFallback() { - fallbackManager.startFallbackTimer(); - List eags = ImmutableList.of( - new EquivalentAddressGroup(ImmutableList.of(new InetSocketAddress(8080)))); - fallbackManager.updateFallbackServers( - eags, Attributes.EMPTY, fallbackPolicy); - - fallbackManager.cancelFallback(); - - fakeClock.forwardTime(FALLBACK_TIMEOUT_MS, TimeUnit.MILLISECONDS); - - assertThat(fallbackManager.isInFallbackMode()).isFalse(); - verify(fakeFallbackLb, never()) - .handleResolvedAddresses(ArgumentMatchers.any(ResolvedAddresses.class)); - } -} diff --git a/xds/src/test/java/io/grpc/xds/LoadStatsStoreImplTest.java b/xds/src/test/java/io/grpc/xds/LoadStatsStoreImplTest.java index 93dc5bb67ba..a68e349cfaf 100644 --- a/xds/src/test/java/io/grpc/xds/LoadStatsStoreImplTest.java +++ b/xds/src/test/java/io/grpc/xds/LoadStatsStoreImplTest.java @@ -24,6 +24,7 @@ import io.envoyproxy.envoy.api.v2.endpoint.EndpointLoadMetricStats; import io.envoyproxy.envoy.api.v2.endpoint.UpstreamLocalityStats; import io.grpc.xds.ClientLoadCounter.MetricValue; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -71,7 +72,8 @@ private static List buildEndpointLoadMetricStatsList( return res; } - private static UpstreamLocalityStats buildUpstreamLocalityStats(XdsLocality locality, + private static UpstreamLocalityStats buildUpstreamLocalityStats( + XdsLocality locality, long callsSucceed, long callsInProgress, long callsFailed, diff --git a/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java b/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java index 81d63a8e2c1..aa72537d6be 100644 --- a/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java +++ b/xds/src/test/java/io/grpc/xds/LocalityStoreTest.java @@ -62,6 +62,10 @@ import io.grpc.internal.FakeClock.TaskFilter; import io.grpc.xds.ClientLoadCounter.LoadRecordingStreamTracerFactory; import io.grpc.xds.ClientLoadCounter.MetricsRecordingListener; +import io.grpc.xds.ClusterLoadAssignmentData.DropOverload; +import io.grpc.xds.ClusterLoadAssignmentData.LbEndpoint; +import io.grpc.xds.ClusterLoadAssignmentData.LocalityInfo; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import io.grpc.xds.InterLocalityPicker.WeightedChildPicker; import io.grpc.xds.LocalityStore.LocalityStoreImpl; import io.grpc.xds.LocalityStore.LocalityStoreImpl.PickerFactory; @@ -69,9 +73,6 @@ import io.grpc.xds.OrcaOobUtil.OrcaReportingConfig; import io.grpc.xds.OrcaOobUtil.OrcaReportingHelperWrapper; import io.grpc.xds.OrcaPerRequestUtil.OrcaPerRequestReportListener; -import io.grpc.xds.XdsComms.DropOverload; -import io.grpc.xds.XdsComms.LbEndpoint; -import io.grpc.xds.XdsComms.LocalityInfo; import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; import java.net.InetSocketAddress; import java.util.Collection; diff --git a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java index 2f4fe4fa77f..377eaa4d8f0 100644 --- a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java +++ b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java @@ -55,10 +55,11 @@ import io.grpc.internal.testing.StreamRecorder; import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; +import io.grpc.xds.ClusterLoadAssignmentData.DropOverload; +import io.grpc.xds.ClusterLoadAssignmentData.LocalityInfo; +import io.grpc.xds.ClusterLoadAssignmentData.XdsLocality; import io.grpc.xds.LoadReportClient.LoadReportCallback; -import io.grpc.xds.XdsComms.AdsStreamCallback; -import io.grpc.xds.XdsComms.DropOverload; -import io.grpc.xds.XdsComms.LocalityInfo; +import io.grpc.xds.LookasideChannelLb.LookasideChannelCallback; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -103,7 +104,7 @@ public void uncaughtException(Thread t, Throwable e) { @Mock private Helper helper; @Mock - private AdsStreamCallback adsStreamCallback; + private LookasideChannelCallback lookasideChannelCallback; @Mock private LoadReportClient loadReportClient; @Mock @@ -168,17 +169,17 @@ public void onCompleted() { doReturn(loadStatsStore).when(localityStore).getLoadStatsStore(); lookasideChannelLb = new LookasideChannelLb( - helper, adsStreamCallback, channel, loadReportClient, localityStore); + helper, lookasideChannelCallback, channel, loadReportClient, localityStore); } @Test public void firstAndSecondEdsResponseReceived() { - verify(adsStreamCallback, never()).onWorking(); + verify(lookasideChannelCallback, never()).onWorking(); verify(loadReportClient, never()).startLoadReporting(any(LoadReportCallback.class)); // first EDS response serverResponseWriter.onNext(edsResponse); - verify(adsStreamCallback).onWorking(); + verify(lookasideChannelCallback).onWorking(); ArgumentCaptor loadReportCallbackCaptor = ArgumentCaptor.forClass(LoadReportCallback.class); verify(loadReportClient).startLoadReporting(loadReportCallbackCaptor.capture()); @@ -186,14 +187,14 @@ public void firstAndSecondEdsResponseReceived() { // second EDS response serverResponseWriter.onNext(edsResponse); - verify(adsStreamCallback, times(1)).onWorking(); + verify(lookasideChannelCallback, times(1)).onWorking(); verify(loadReportClient, times(1)).startLoadReporting(any(LoadReportCallback.class)); verify(localityStore, never()).updateOobMetricsReportInterval(anyLong()); loadReportCallback.onReportResponse(1234); verify(localityStore).updateOobMetricsReportInterval(1234); - verify(adsStreamCallback, never()).onError(); + verify(lookasideChannelCallback, never()).onError(); lookasideChannelLb.shutdown(); } @@ -235,7 +236,7 @@ public void handleDropUpdates() { .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") .build()); - verify(adsStreamCallback, never()).onAllDrop(); + verify(lookasideChannelCallback, never()).onAllDrop(); verify(localityStore).updateDropPercentage(ImmutableList.of( new DropOverload("cat_1", 300_00), new DropOverload("cat_2", 45_00), @@ -270,12 +271,12 @@ public void handleDropUpdates() { .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") .build()); - verify(adsStreamCallback).onAllDrop(); + verify(lookasideChannelCallback).onAllDrop(); verify(localityStore).updateDropPercentage(ImmutableList.of( new DropOverload("cat_1", 300_00), new DropOverload("cat_2", 100_00_00))); - verify(adsStreamCallback, never()).onError(); + verify(lookasideChannelCallback, never()).onError(); lookasideChannelLb.shutdown(); } @@ -348,13 +349,13 @@ public void handleLocalityAssignmentUpdates() { XdsLocality locality1 = XdsLocality.fromLocalityProto(localityProto1); LocalityInfo localityInfo1 = new LocalityInfo( ImmutableList.of( - new XdsComms.LbEndpoint(endpoint11), - new XdsComms.LbEndpoint(endpoint12)), + new ClusterLoadAssignmentData.LbEndpoint(endpoint11), + new ClusterLoadAssignmentData.LbEndpoint(endpoint12)), 1, 0); LocalityInfo localityInfo2 = new LocalityInfo( ImmutableList.of( - new XdsComms.LbEndpoint(endpoint21), - new XdsComms.LbEndpoint(endpoint22)), + new ClusterLoadAssignmentData.LbEndpoint(endpoint21), + new ClusterLoadAssignmentData.LbEndpoint(endpoint22)), 2, 0); XdsLocality locality2 = XdsLocality.fromLocalityProto(localityProto2); @@ -364,16 +365,16 @@ public void handleLocalityAssignmentUpdates() { assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( locality1, localityInfo1, locality2, localityInfo2).inOrder(); - verify(adsStreamCallback, never()).onError(); + verify(lookasideChannelCallback, never()).onError(); lookasideChannelLb.shutdown(); } @Test public void verifyRpcErrorPropagation() { - verify(adsStreamCallback, never()).onError(); + verify(lookasideChannelCallback, never()).onError(); serverResponseWriter.onError(new RuntimeException()); - verify(adsStreamCallback).onError(); + verify(lookasideChannelCallback).onError(); } @Test @@ -397,8 +398,8 @@ public void reportLoadAfterReceivingFirstEdsResponseUntilShutdown() { // Simulates a syntactically incorrect EDS response. serverResponseWriter.onNext(DiscoveryResponse.getDefaultInstance()); verify(loadReportClient, never()).startLoadReporting(any(LoadReportCallback.class)); - verify(adsStreamCallback, never()).onWorking(); - verify(adsStreamCallback, never()).onError(); + verify(lookasideChannelCallback, never()).onWorking(); + verify(lookasideChannelCallback, never()).onError(); // Simulate a syntactically correct EDS response. DiscoveryResponse edsResponse = @@ -408,7 +409,7 @@ public void reportLoadAfterReceivingFirstEdsResponseUntilShutdown() { .build(); serverResponseWriter.onNext(edsResponse); - verify(adsStreamCallback).onWorking(); + verify(lookasideChannelCallback).onWorking(); ArgumentCaptor lrsCallbackCaptor = ArgumentCaptor.forClass(null); verify(loadReportClient).startLoadReporting(lrsCallbackCaptor.capture()); @@ -417,13 +418,15 @@ public void reportLoadAfterReceivingFirstEdsResponseUntilShutdown() { // Simulate another EDS response from the same remote balancer. serverResponseWriter.onNext(edsResponse); - verifyNoMoreInteractions(adsStreamCallback, loadReportClient); + verifyNoMoreInteractions(lookasideChannelCallback, loadReportClient); // Simulate an EDS error response. serverResponseWriter.onError(Status.ABORTED.asException()); - verify(adsStreamCallback).onError(); + verify(lookasideChannelCallback).onError(); - verifyNoMoreInteractions(adsStreamCallback, loadReportClient); + verifyNoMoreInteractions(lookasideChannelCallback, loadReportClient); verify(localityStore, times(1)).updateOobMetricsReportInterval(anyLong()); // only once + + lookasideChannelLb.shutdown(); } } diff --git a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java index 9a13cf52e97..dde8eb0cb95 100644 --- a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java +++ b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java @@ -33,8 +33,8 @@ import io.grpc.LoadBalancer.SubchannelPicker; import io.grpc.LoadBalancerRegistry; import io.grpc.internal.JsonParser; +import io.grpc.xds.LookasideChannelLb.LookasideChannelCallback; import io.grpc.xds.LookasideLb.LookasideChannelLbFactory; -import io.grpc.xds.XdsComms.AdsStreamCallback; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -55,7 +55,7 @@ public class LookasideLbTest { new LookasideChannelLbFactory() { @Override public LoadBalancer newLoadBalancer( - Helper helper, AdsStreamCallback adsCallback, String balancerName) { + Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName) { // just return a mock and record helper and balancer. helpers.add(helper); LoadBalancer balancer = mock(LoadBalancer.class); @@ -65,7 +65,8 @@ public LoadBalancer newLoadBalancer( }; private LoadBalancer lookasideLb = new LookasideLb( - helper, mock(AdsStreamCallback.class), lookasideChannelLbFactory, new LoadBalancerRegistry()); + helper, mock(LookasideChannelCallback.class), lookasideChannelLbFactory, + new LoadBalancerRegistry()); @Test @@ -163,7 +164,7 @@ public void handleChildPolicyChangeThenBalancerNameChangeThenChildPolicyChange() public void handleResolvedAddress_createLbChannel() throws Exception { // Test balancer created with the default real LookasideChannelLbFactory - lookasideLb = new LookasideLb(helper, mock(AdsStreamCallback.class)); + lookasideLb = new LookasideLb(helper, mock(LookasideChannelCallback.class)); String lbConfigRaw11 = "{'balancerName' : 'dns:///balancer1.example.com:8080'}" .replace("'", "\""); @SuppressWarnings("unchecked") diff --git a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java index c69e689ebc6..1b61655a7e2 100644 --- a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java @@ -30,12 +30,9 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import com.google.protobuf.Any; import com.google.protobuf.UInt32Value; import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; -import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy; import io.envoyproxy.envoy.api.v2.DiscoveryRequest; import io.envoyproxy.envoy.api.v2.DiscoveryResponse; import io.envoyproxy.envoy.api.v2.core.Address; @@ -45,8 +42,6 @@ import io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint; import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase; -import io.envoyproxy.envoy.type.FractionalPercent; -import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; import io.grpc.ChannelLogger; import io.grpc.LoadBalancer; import io.grpc.LoadBalancer.Helper; @@ -62,23 +57,19 @@ import io.grpc.internal.testing.StreamRecorder; import io.grpc.stub.StreamObserver; import io.grpc.testing.GrpcCleanupRule; -import io.grpc.xds.XdsComms.AdsStreamCallback; -import io.grpc.xds.XdsComms.DropOverload; -import io.grpc.xds.XdsComms.LocalityInfo; +import io.grpc.xds.XdsComms2.AdsStreamCallback; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; /** - * Unit tests for {@link XdsComms}. + * Unit tests for {@link XdsComms2}. */ @RunWith(JUnit4.class) public class XdsCommsTest { @@ -99,15 +90,11 @@ public boolean shouldAccept(Runnable command) { @Mock private AdsStreamCallback adsStreamCallback; @Mock - private LocalityStore localityStore; - @Mock private BackoffPolicy.Provider backoffPolicyProvider; @Mock private BackoffPolicy backoffPolicy1; @Mock private BackoffPolicy backoffPolicy2; - @Captor - private ArgumentCaptor> localityEndpointsMappingCaptor; private final FakeClock fakeClock = new FakeClock(); private final SynchronizationContext syncContext = new SynchronizationContext( @@ -123,7 +110,7 @@ public void uncaughtException(Thread t, Throwable e) { private StreamObserver responseWriter; private ManagedChannel channel; - private XdsComms xdsComms; + private XdsComms2 xdsComms; @Before public void setUp() throws Exception { @@ -195,14 +182,14 @@ public LoadBalancer newLoadBalancer(Helper helper) { doReturn(backoffPolicy1, backoffPolicy2).when(backoffPolicyProvider).get(); doReturn(10L, 100L, 1000L).when(backoffPolicy1).nextBackoffNanos(); doReturn(20L, 200L).when(backoffPolicy2).nextBackoffNanos(); - xdsComms = new XdsComms( - channel, helper, adsStreamCallback, localityStore, backoffPolicyProvider, + xdsComms = new XdsComms2( + channel, helper, adsStreamCallback, backoffPolicyProvider, fakeClock.getStopwatchSupplier()); } @Test public void shutdownLbRpc_verifyChannelNotShutdown() throws Exception { - xdsComms.shutdownLbRpc("shutdown msg1"); + xdsComms.shutdownLbRpc(); assertTrue(streamRecorder.awaitCompletion(1, TimeUnit.SECONDS)); assertEquals(Status.Code.CANCELLED, Status.fromThrowable(streamRecorder.getError()).getCode()); assertFalse(channel.isShutdown()); @@ -210,13 +197,13 @@ public void shutdownLbRpc_verifyChannelNotShutdown() throws Exception { @Test public void cancel() throws Exception { - xdsComms.shutdownLbRpc("cause1"); + xdsComms.shutdownLbRpc(); assertTrue(streamRecorder.awaitCompletion(1, TimeUnit.SECONDS)); assertEquals(Status.Code.CANCELLED, Status.fromThrowable(streamRecorder.getError()).getCode()); } @Test - public void standardMode_sendEdsRequest_getEdsResponse_withNoDrop() { + public void handleEdsResponse() { assertThat(streamRecorder.getValues()).hasSize(1); DiscoveryRequest request = streamRecorder.getValues().get(0); assertThat(request.getTypeUrl()).isEqualTo(EDS_TYPE_URL); @@ -266,212 +253,52 @@ public void standardMode_sendEdsRequest_getEdsResponse_withNoDrop() { .setAddress("addr31").setPortValue(31)))) .setLoadBalancingWeight(UInt32Value.of(31)) .build(); + ClusterLoadAssignment clusterLoadAssignment = ClusterLoadAssignment.newBuilder() + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto1) + .addLbEndpoints(endpoint11) + .addLbEndpoints(endpoint12) + .setLoadBalancingWeight(UInt32Value.of(1))) + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto2) + .addLbEndpoints(endpoint21) + .addLbEndpoints(endpoint22) + .setLoadBalancingWeight(UInt32Value.of(2))) + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto3) + .addLbEndpoints(endpoint3) + .setLoadBalancingWeight(UInt32Value.of(0))) + .build(); DiscoveryResponse edsResponse = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .addLbEndpoints(endpoint12) - .setLoadBalancingWeight(UInt32Value.of(1))) - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto2) - .addLbEndpoints(endpoint21) - .addLbEndpoints(endpoint22) - .setLoadBalancingWeight(UInt32Value.of(2))) - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto3) - .addLbEndpoints(endpoint3) - .setLoadBalancingWeight(UInt32Value.of(0))) - .build())) + .addResources(Any.pack(clusterLoadAssignment)) .setTypeUrl(EDS_TYPE_URL) .build(); responseWriter.onNext(edsResponse); - verify(adsStreamCallback).onWorking(); - - XdsLocality locality1 = XdsLocality.fromLocalityProto(localityProto1); - LocalityInfo localityInfo1 = new LocalityInfo( - ImmutableList.of( - new XdsComms.LbEndpoint(endpoint11), - new XdsComms.LbEndpoint(endpoint12)), - 1, - 0); - LocalityInfo localityInfo2 = new LocalityInfo( - ImmutableList.of( - new XdsComms.LbEndpoint(endpoint21), - new XdsComms.LbEndpoint(endpoint22)), - 2, - 0); - XdsLocality locality2 = XdsLocality.fromLocalityProto(localityProto2); - - InOrder inOrder = inOrder(localityStore); - inOrder.verify(localityStore).updateDropPercentage(ImmutableList.of()); - inOrder.verify(localityStore).updateLocalityStore(localityEndpointsMappingCaptor.capture()); - assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( - locality1, localityInfo1, locality2, localityInfo2).inOrder(); - - + verify(adsStreamCallback).onEdsResponse(clusterLoadAssignment); + + ClusterLoadAssignment clusterLoadAssignment2 = ClusterLoadAssignment.newBuilder() + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto2) + .addLbEndpoints(endpoint21) + .addLbEndpoints(endpoint22) + .setLoadBalancingWeight(UInt32Value.of(2))) + .addEndpoints(LocalityLbEndpoints.newBuilder() + .setLocality(localityProto1) + .addLbEndpoints(endpoint11) + .addLbEndpoints(endpoint12) + .setLoadBalancingWeight(UInt32Value.of(1))) + .build(); edsResponse = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto2) - .addLbEndpoints(endpoint21) - .addLbEndpoints(endpoint22) - .setLoadBalancingWeight(UInt32Value.of(2))) - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .addLbEndpoints(endpoint12) - .setLoadBalancingWeight(UInt32Value.of(1))) - .build())) + .addResources(Any.pack(clusterLoadAssignment2)) .setTypeUrl(EDS_TYPE_URL) .build(); responseWriter.onNext(edsResponse); - verify(adsStreamCallback, times(1)).onWorking(); + verify(adsStreamCallback).onEdsResponse(clusterLoadAssignment2); verifyNoMoreInteractions(adsStreamCallback); - inOrder.verify(localityStore).updateDropPercentage(ImmutableList.of()); - inOrder.verify(localityStore).updateLocalityStore(localityEndpointsMappingCaptor.capture()); - assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( - locality2, localityInfo2, locality1, localityInfo1).inOrder(); - - xdsComms.shutdownLbRpc("End test"); - } - - @Test - public void standardMode_sendEdsRequest_getEdsResponse_withDrops() { - Locality localityProto1 = Locality.newBuilder() - .setRegion("region1").setZone("zone1").setSubZone("subzone1").build(); - LbEndpoint endpoint11 = LbEndpoint.newBuilder() - .setEndpoint(Endpoint.newBuilder() - .setAddress(Address.newBuilder() - .setSocketAddress(SocketAddress.newBuilder() - .setAddress("addr11").setPortValue(11)))) - .setLoadBalancingWeight(UInt32Value.of(11)) - .build(); - Locality localityProto2 = Locality.newBuilder() - .setRegion("region2").setZone("zone2").setSubZone("subzone2").build(); - LbEndpoint endpoint21 = LbEndpoint.newBuilder() - .setEndpoint(Endpoint.newBuilder() - .setAddress(Address.newBuilder() - .setSocketAddress(SocketAddress.newBuilder() - .setAddress("addr21").setPortValue(21)))) - .setLoadBalancingWeight(UInt32Value.of(21)) - .build(); - DiscoveryResponse edsResponseWithDrops = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto2) - .addLbEndpoints(endpoint21) - .setLoadBalancingWeight(UInt32Value.of(2))) - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .setLoadBalancingWeight(UInt32Value.of(1))) - .setPolicy(Policy.newBuilder() - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("throttle") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(123).setDenominator(DenominatorType.MILLION).build()) - .build()) - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("lb") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(456).setDenominator(DenominatorType.TEN_THOUSAND).build()) - .build()) - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("fake_category") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(78).setDenominator(DenominatorType.HUNDRED).build()) - .build()) - .build()) - .build())) - .setTypeUrl(EDS_TYPE_URL) - .build(); - responseWriter.onNext(edsResponseWithDrops); - - verify(adsStreamCallback).onWorking(); - verifyNoMoreInteractions(adsStreamCallback); - InOrder inOrder = inOrder(localityStore); - inOrder.verify(localityStore).updateDropPercentage(ImmutableList.of( - new DropOverload("throttle", 123), - new DropOverload("lb", 456_00), - new DropOverload("fake_category", 78_00_00))); - inOrder.verify(localityStore).updateLocalityStore(localityEndpointsMappingCaptor.capture()); - - XdsLocality locality1 = XdsLocality.fromLocalityProto(localityProto1); - LocalityInfo localityInfo1 = new LocalityInfo( - ImmutableList.of(new XdsComms.LbEndpoint(endpoint11)), 1, 0); - LocalityInfo localityInfo2 = new LocalityInfo( - ImmutableList.of(new XdsComms.LbEndpoint(endpoint21)), 2, 0); - XdsLocality locality2 = XdsLocality.fromLocalityProto(localityProto2); - assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( - locality2, localityInfo2, locality1, localityInfo1).inOrder(); - - DiscoveryResponse edsResponseWithAllDrops = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto2) - .addLbEndpoints(endpoint21) - .setLoadBalancingWeight(UInt32Value.of(2))) - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .setLoadBalancingWeight(UInt32Value.of(1))) - .setPolicy(Policy.newBuilder() - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("throttle") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(123).setDenominator(DenominatorType.MILLION).build()) - .build()) - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("lb") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(456).setDenominator(DenominatorType.TEN_THOUSAND).build()) - .build()) - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("fake_category") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(789).setDenominator(DenominatorType.HUNDRED).build()) - .build()) - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("fake_category_2") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(78).setDenominator(DenominatorType.HUNDRED).build()) - .build()) - .build()) - .build())) - .setTypeUrl(EDS_TYPE_URL) - .build(); - responseWriter.onNext(edsResponseWithAllDrops); - - verify(adsStreamCallback, times(1)).onWorking(); - verify(adsStreamCallback).onAllDrop(); - verify(adsStreamCallback, never()).onError(); - inOrder.verify(localityStore).updateDropPercentage(ImmutableList.of( - new DropOverload("throttle", 123), - new DropOverload("lb", 456_00), - new DropOverload("fake_category", 1000_000))); - inOrder.verify(localityStore).updateLocalityStore(localityEndpointsMappingCaptor.capture()); - assertThat(localityEndpointsMappingCaptor.getValue()).containsExactly( - locality2, localityInfo2, locality1, localityInfo1).inOrder(); - - xdsComms.shutdownLbRpc("End test"); + xdsComms.shutdownLbRpc(); } @Test @@ -500,7 +327,7 @@ public void serverOnCompleteShouldFailClient() { * Verify retry is scheduled. Verify the 6th PRC starts after backoff. * *

    The 6th RPC fails with response observer onError() without receiving initial response. - * Verify retry is scheduled. Call {@link XdsComms#shutdownLbRpc(String)}, verify retry timer is + * Verify retry is scheduled. Call {@link XdsComms2#shutdownLbRpc()}, verify retry timer is * cancelled. */ @Test @@ -653,7 +480,7 @@ public void adsRpcRetry() { assertEquals(1, fakeClock.numPendingTasks(LB_RPC_RETRY_TASK_FILTER)); // Shutdown cancels retry - xdsComms.shutdownLbRpc("shutdown"); + xdsComms.shutdownLbRpc(); assertEquals(0, fakeClock.numPendingTasks(LB_RPC_RETRY_TASK_FILTER)); } @@ -666,6 +493,6 @@ public void refreshAdsStreamCancelsExistingRetry() { xdsComms.refreshAdsStream(); assertEquals(0, fakeClock.numPendingTasks(LB_RPC_RETRY_TASK_FILTER)); - xdsComms.shutdownLbRpc("End test"); + xdsComms.shutdownLbRpc(); } } diff --git a/xds/src/test/java/io/grpc/xds/XdsLbStateTest.java b/xds/src/test/java/io/grpc/xds/XdsLbStateTest.java deleted file mode 100644 index 84b6125ad78..00000000000 --- a/xds/src/test/java/io/grpc/xds/XdsLbStateTest.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import com.google.common.collect.ImmutableList; -import io.envoyproxy.envoy.api.v2.DiscoveryRequest; -import io.envoyproxy.envoy.api.v2.DiscoveryResponse; -import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase; -import io.grpc.Attributes; -import io.grpc.ChannelLogger; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer.Helper; -import io.grpc.ManagedChannel; -import io.grpc.SynchronizationContext; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.internal.BackoffPolicy; -import io.grpc.internal.FakeClock; -import io.grpc.internal.testing.StreamRecorder; -import io.grpc.stub.StreamObserver; -import io.grpc.testing.GrpcCleanupRule; -import io.grpc.xds.XdsComms.AdsStreamCallback; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Unit tests for {@link XdsLbState}. - */ -@RunWith(JUnit4.class) -public class XdsLbStateTest { - private static final String BALANCER_NAME = "balancerName"; - @Rule - public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); - @Mock - private Helper helper; - @Mock - private AdsStreamCallback adsStreamCallback; - @Mock - private LocalityStore localityStore; - @Mock - private BackoffPolicy.Provider backoffPolicyProvider; - - private final FakeClock fakeClock = new FakeClock(); - - private final SynchronizationContext syncContext = new SynchronizationContext( - new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - throw new AssertionError(e); - } - }); - - private final StreamRecorder streamRecorder = StreamRecorder.create(); - private ManagedChannel channel; - private XdsLbState xdsLbState; - - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - doReturn(syncContext).when(helper).getSynchronizationContext(); - doReturn(fakeClock.getScheduledExecutorService()).when(helper).getScheduledExecutorService(); - doReturn("fake_authority").when(helper).getAuthority(); - doReturn(mock(ChannelLogger.class)).when(helper).getChannelLogger(); - - String serverName = InProcessServerBuilder.generateName(); - - AggregatedDiscoveryServiceImplBase serviceImpl = new AggregatedDiscoveryServiceImplBase() { - @Override - public StreamObserver streamAggregatedResources( - final StreamObserver responseObserver) { - return new StreamObserver() { - - @Override - public void onNext(DiscoveryRequest value) { - streamRecorder.onNext(value); - } - - @Override - public void onError(Throwable t) { - streamRecorder.onError(t); - } - - @Override - public void onCompleted() { - streamRecorder.onCompleted(); - responseObserver.onCompleted(); - } - }; - } - }; - - cleanupRule.register( - InProcessServerBuilder - .forName(serverName) - .addService(serviceImpl) - .directExecutor() - .build() - .start()); - channel = - cleanupRule.register(InProcessChannelBuilder.forName(serverName).directExecutor().build()); - doReturn(channel).when(helper).createResolvingOobChannel(BALANCER_NAME); - - xdsLbState = new XdsLbState( - BALANCER_NAME, null, helper, localityStore, channel, adsStreamCallback, - backoffPolicyProvider); - } - - @Test - public void shutdownResetsLocalityStore() { - xdsLbState.shutdownAndReleaseChannel("Client shutdown"); - verify(localityStore).reset(); - } - - @Test - public void shutdownDoesNotTearDownChannel() { - ManagedChannel lbChannel = xdsLbState.shutdownAndReleaseChannel("Client shutdown"); - assertThat(lbChannel).isSameInstanceAs(channel); - assertThat(channel.isShutdown()).isFalse(); - } - - @Test - public void handleResolvedAddressGroupsTriggerEds() throws Exception { - xdsLbState.handleResolvedAddressGroups( - ImmutableList.of(), Attributes.EMPTY); - - assertThat(streamRecorder.firstValue().get().getTypeUrl()) - .isEqualTo("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment"); - - xdsLbState.shutdownAndReleaseChannel("End test"); - } -} diff --git a/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java b/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java index f52d17844f1..99e802d92f2 100644 --- a/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java +++ b/xds/src/test/java/io/grpc/xds/XdsLoadBalancer2Test.java @@ -40,7 +40,7 @@ import io.grpc.Status; import io.grpc.SynchronizationContext; import io.grpc.internal.FakeClock; -import io.grpc.xds.XdsComms.AdsStreamCallback; +import io.grpc.xds.LookasideChannelLb.LookasideChannelCallback; import io.grpc.xds.XdsLoadBalancer2.LookasideLbFactory; import java.util.ArrayList; import java.util.List; @@ -75,7 +75,7 @@ public void uncaughtException(Thread t, Throwable e) { @Mock private Helper helper; private LoadBalancer xdsLoadBalancer; - private AdsStreamCallback adsCallback; + private LookasideChannelCallback lookasideChannelCallback; private Helper lookasideLbHelper; private final List lookasideLbs = new ArrayList<>(); @@ -89,10 +89,11 @@ public void uncaughtException(Thread t, Throwable e) { public void setUp() { LookasideLbFactory lookasideLbFactory = new LookasideLbFactory() { @Override - public LoadBalancer newLoadBalancer(Helper helper, AdsStreamCallback adsCallback) { + public LoadBalancer newLoadBalancer( + Helper helper, LookasideChannelCallback lookasideChannelCallback) { // just return a mock and record the input and output lookasideLbHelper = helper; - XdsLoadBalancer2Test.this.adsCallback = adsCallback; + XdsLoadBalancer2Test.this.lookasideChannelCallback = lookasideChannelCallback; LoadBalancer lookasideLb = mock(LoadBalancer.class); lookasideLbs.add(lookasideLb); return lookasideLb; @@ -141,7 +142,7 @@ public void canHandleEmptyAddressListFromNameResolution() { public void timeoutAtStartup_expectUseFallback_thenBackendReady_expectExitFallback() { verifyNotInFallbackMode(); fakeClock.forwardTime(9, TimeUnit.SECONDS); - adsCallback.onWorking(); + lookasideChannelCallback.onWorking(); verifyNotInFallbackMode(); fakeClock.forwardTime(1, TimeUnit.SECONDS); verifyInFallbackMode(); @@ -161,7 +162,7 @@ public void backendReadyBeforeTimeoutAtStartup_expectNoFallback() { verifyNotInFallbackMode(); assertThat(fakeClock.getPendingTasks()).hasSize(1); - adsCallback.onWorking(); + lookasideChannelCallback.onWorking(); SubchannelPicker subchannelPicker = mock(SubchannelPicker.class); lookasideLbHelper.updateBalancingState(READY, subchannelPicker); verify(helper).updateBalancingState(READY, subchannelPicker); @@ -176,7 +177,7 @@ public void recevieAllDropBeforeTimeoutAtStartup_expectNoFallback() { verifyNotInFallbackMode(); assertThat(fakeClock.getPendingTasks()).hasSize(1); - adsCallback.onAllDrop(); + lookasideChannelCallback.onAllDrop(); assertThat(fakeClock.getPendingTasks()).isEmpty(); verifyNotInFallbackMode(); @@ -188,7 +189,7 @@ public void lookasideChannelFailsWithoutSeeingEdsResponseBeforeTimeoutAtStartup( verifyNotInFallbackMode(); assertThat(fakeClock.getPendingTasks()).hasSize(1); - adsCallback.onError(); + lookasideChannelCallback.onError(); verifyInFallbackMode(); assertThat(fallbackLbs).hasSize(1); @@ -198,8 +199,8 @@ public void lookasideChannelFailsWithoutSeeingEdsResponseBeforeTimeoutAtStartup( public void lookasideChannelSeeingEdsResponseThenFailsBeforeTimeoutAtStartup() { verifyNotInFallbackMode(); assertThat(fakeClock.getPendingTasks()).hasSize(1); - adsCallback.onWorking(); - adsCallback.onError(); + lookasideChannelCallback.onWorking(); + lookasideChannelCallback.onError(); verifyNotInFallbackMode(); fakeClock.forwardTime(10, TimeUnit.SECONDS); @@ -220,7 +221,7 @@ public void fallbackWillHandleLastResolvedAddresses() { .build(); xdsLoadBalancer.handleResolvedAddresses(resolvedAddresses); - adsCallback.onError(); + lookasideChannelCallback.onError(); LoadBalancer fallbackLb = Iterables.getLast(fallbackLbs); verify(fallbackLb).handleResolvedAddresses(same(resolvedAddresses)); } diff --git a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java b/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java deleted file mode 100644 index d6c9a8a5458..00000000000 --- a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerTest.java +++ /dev/null @@ -1,812 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.truth.Truth.assertThat; -import static io.grpc.ConnectivityState.CONNECTING; -import static io.grpc.ConnectivityState.READY; -import static io.grpc.ConnectivityState.TRANSIENT_FAILURE; -import static io.grpc.LoadBalancer.ATTR_LOAD_BALANCING_CONFIG; -import static io.grpc.xds.XdsSubchannelPickers.BUFFER_PICKER; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.AdditionalAnswers.delegatesTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.isA; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; - -import com.google.protobuf.Any; -import com.google.protobuf.UInt32Value; -import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; -import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy; -import io.envoyproxy.envoy.api.v2.DiscoveryRequest; -import io.envoyproxy.envoy.api.v2.DiscoveryResponse; -import io.envoyproxy.envoy.api.v2.core.Address; -import io.envoyproxy.envoy.api.v2.core.Locality; -import io.envoyproxy.envoy.api.v2.core.SocketAddress; -import io.envoyproxy.envoy.api.v2.endpoint.Endpoint; -import io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint; -import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; -import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase; -import io.envoyproxy.envoy.type.FractionalPercent; -import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; -import io.grpc.Attributes; -import io.grpc.CallOptions; -import io.grpc.ChannelLogger; -import io.grpc.ConnectivityState; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer; -import io.grpc.LoadBalancer.Helper; -import io.grpc.LoadBalancer.PickSubchannelArgs; -import io.grpc.LoadBalancer.ResolvedAddresses; -import io.grpc.LoadBalancer.SubchannelPicker; -import io.grpc.LoadBalancerProvider; -import io.grpc.LoadBalancerRegistry; -import io.grpc.ManagedChannel; -import io.grpc.MethodDescriptor; -import io.grpc.Status; -import io.grpc.SynchronizationContext; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.internal.BackoffPolicy; -import io.grpc.internal.FakeClock; -import io.grpc.internal.FakeClock.TaskFilter; -import io.grpc.internal.JsonParser; -import io.grpc.internal.testing.StreamRecorder; -import io.grpc.stub.StreamObserver; -import io.grpc.testing.GrpcCleanupRule; -import io.grpc.xds.XdsSubchannelPickers.ErrorPicker; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatchers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Unit tests for {@link XdsLoadBalancer}. - */ -@RunWith(JUnit4.class) -public class XdsLoadBalancerTest { - @Rule - public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); - @Mock - private Helper helper; - @Mock - private LoadBalancer fallbackBalancer1; - @Mock - private LoadBalancer fakeBalancer2; - @Mock - private BackoffPolicy.Provider backoffPolicyProvider; - private XdsLoadBalancer lb; - - private final FakeClock fakeClock = new FakeClock(); - private final StreamRecorder streamRecorder = StreamRecorder.create(); - - private final LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry(); - - private Helper fallbackHelper1; - - private final LoadBalancerProvider lbProvider1 = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return "fallback_1"; - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - fallbackHelper1 = helper; - return fallbackBalancer1; - } - }; - - private final LoadBalancerProvider lbProvider2 = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return "supported_2"; - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - return fakeBalancer2; - } - }; - - private final Locality localityProto1 = Locality.newBuilder() - .setRegion("region1").setZone("zone1").setSubZone("subzone1").build(); - private final LbEndpoint endpoint11 = LbEndpoint.newBuilder() - .setEndpoint(Endpoint.newBuilder() - .setAddress(Address.newBuilder() - .setSocketAddress(SocketAddress.newBuilder() - .setAddress("addr11").setPortValue(11)))) - .setLoadBalancingWeight(UInt32Value.of(11)) - .build(); - private final DiscoveryResponse edsResponse = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .setLoadBalancingWeight(UInt32Value.of(1))) - .build())) - .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") - .build(); - - private Helper childHelper; - @Mock - private LoadBalancer childBalancer; - - private final LoadBalancerProvider roundRobin = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return "round_robin"; - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - childHelper = helper; - return childBalancer; - } - }; - - private final SynchronizationContext syncContext = new SynchronizationContext( - new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - throw new AssertionError(e); - } - }); - - private final TaskFilter fallbackTaskFilter = new TaskFilter() { - @Override - public boolean shouldAccept(Runnable runnable) { - return runnable.toString().contains("FallbackTask"); - } - }; - - private ManagedChannel oobChannel1; - private ManagedChannel oobChannel2; - private ManagedChannel oobChannel3; - - private StreamObserver serverResponseWriter; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - lbRegistry.register(lbProvider1); - lbRegistry.register(lbProvider2); - lbRegistry.register(roundRobin); - lb = new XdsLoadBalancer(helper, lbRegistry, backoffPolicyProvider); - doReturn(syncContext).when(helper).getSynchronizationContext(); - doReturn(fakeClock.getScheduledExecutorService()).when(helper).getScheduledExecutorService(); - doReturn(mock(ChannelLogger.class)).when(helper).getChannelLogger(); - doReturn("fake_authority").when(helper).getAuthority(); - - String serverName = InProcessServerBuilder.generateName(); - - AggregatedDiscoveryServiceImplBase serviceImpl = new AggregatedDiscoveryServiceImplBase() { - @Override - public StreamObserver streamAggregatedResources( - final StreamObserver responseObserver) { - serverResponseWriter = responseObserver; - - return new StreamObserver() { - - @Override - public void onNext(DiscoveryRequest value) { - streamRecorder.onNext(value); - } - - @Override - public void onError(Throwable t) { - streamRecorder.onError(t); - } - - @Override - public void onCompleted() { - streamRecorder.onCompleted(); - responseObserver.onCompleted(); - } - }; - } - }; - - cleanupRule.register( - InProcessServerBuilder - .forName(serverName) - .directExecutor() - .addService(serviceImpl) - .build() - .start()); - - InProcessChannelBuilder channelBuilder = - InProcessChannelBuilder.forName(serverName).directExecutor(); - oobChannel1 = mock( - ManagedChannel.class, - delegatesTo(cleanupRule.register(channelBuilder.build()))); - oobChannel2 = mock( - ManagedChannel.class, - delegatesTo(cleanupRule.register(channelBuilder.build()))); - oobChannel3 = mock( - ManagedChannel.class, - delegatesTo(cleanupRule.register(channelBuilder.build()))); - - doReturn(oobChannel1).doReturn(oobChannel2).doReturn(oobChannel3) - .when(helper).createResolvingOobChannel(anyString()); - - // To write less tedious code for tests, allow fallbackBalancer to handle empty address list. - doReturn(true).when(fallbackBalancer1).canHandleEmptyAddressListFromNameResolution(); - } - - @After - public void tearDown() { - lb.shutdown(); - } - - @Test - public void canHandleEmptyAddressListFromNameResolution() { - assertTrue(lb.canHandleEmptyAddressListFromNameResolution()); - } - - @Test - public void resolverEvent_standardModeToStandardMode() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - Attributes attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - XdsLbState xdsLbState1 = lb.getXdsLbStateForTest(); - assertThat(xdsLbState1.childPolicy).isNull(); - verify(helper).createResolvingOobChannel(anyString()); - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - - - lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig2 = (Map) JsonParser.parse(lbConfigRaw); - attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig2).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - XdsLbState xdsLbState2 = lb.getXdsLbStateForTest(); - assertThat(xdsLbState2.childPolicy).isNull(); - assertThat(xdsLbState2).isSameInstanceAs(xdsLbState1); - - // verify oobChannel is unchanged - verify(helper).createResolvingOobChannel(anyString()); - // verify ADS stream is unchanged - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - } - - @Test - public void resolverEvent_standardModeToCustomMode() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - Attributes attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - verify(helper).createResolvingOobChannel(anyString()); - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - - lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"supported_2\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig2 = (Map) JsonParser.parse(lbConfigRaw); - attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig2).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - assertThat(lb.getXdsLbStateForTest().childPolicy).isNotNull(); - - // verify oobChannel is unchanged - verify(helper).createResolvingOobChannel(anyString()); - // verify ADS stream is reset - verify(oobChannel1, times(2)) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - } - - @Test - public void resolverEvent_customModeToStandardMode() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"supported_2\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - Attributes attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - verify(helper).createResolvingOobChannel(anyString()); - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - - assertThat(lb.getXdsLbStateForTest().childPolicy).isNotNull(); - - lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig2 = (Map) JsonParser.parse(lbConfigRaw); - attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig2).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - assertThat(lb.getXdsLbStateForTest().childPolicy).isNull(); - - // verify oobChannel is unchanged - verify(helper).createResolvingOobChannel(anyString()); - // verify ADS stream is reset - verify(oobChannel1, times(2)) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - } - - @Test - public void resolverEvent_customModeToCustomMode() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"supported_2\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - Attributes attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - assertThat(lb.getXdsLbStateForTest().childPolicy).isNotNull(); - verify(helper).createResolvingOobChannel(anyString()); - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - - lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"fallback_1\" : {\"key\" : \"val\"}}, {\"unfallback_1\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig2 = (Map) JsonParser.parse(lbConfigRaw); - attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig2).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - assertThat(lb.getXdsLbStateForTest().childPolicy).isNotNull(); - // verify oobChannel is unchanged - verify(helper).createResolvingOobChannel(anyString()); - // verify ADS stream is reset - verify(oobChannel1, times(2)) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - } - - @Test - public void resolverEvent_balancerNameChange() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - Attributes attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - verify(helper).createResolvingOobChannel(anyString()); - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - - lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8443\"," - + "\"childPolicy\" : [{\"fallback_1\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig2 = (Map) JsonParser.parse(lbConfigRaw); - attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig2).build(); - - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - assertThat(lb.getXdsLbStateForTest().childPolicy).isNotNull(); - - // verify oobChannel is unchanged - verify(helper, times(2)).createResolvingOobChannel(anyString()); - verify(oobChannel1) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - verify(oobChannel2) - .newCall(ArgumentMatchers.>any(), - ArgumentMatchers.any()); - verifyNoMoreInteractions(oobChannel3); - } - - @Test - public void resolutionErrorAtStartup() { - lb.handleNameResolutionError(Status.UNAVAILABLE); - - assertNull(childHelper); - assertNull(fallbackHelper1); - verify(helper).updateBalancingState(same(TRANSIENT_FAILURE), isA(ErrorPicker.class)); - } - - @Test - public void resolutionErrorAtFallback() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - // let fallback timer expire - assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1); - ArgumentCaptor captor = ArgumentCaptor.forClass(ResolvedAddresses.class); - verify(fallbackBalancer1).handleResolvedAddresses(captor.capture()); - assertThat(captor.getValue().getAttributes().get(ATTR_LOAD_BALANCING_CONFIG)) - .containsExactly("fallback_1_option", "yes"); - - Status status = Status.UNAVAILABLE.withDescription("resolution error"); - lb.handleNameResolutionError(status); - verify(fallbackBalancer1).handleNameResolutionError(status); - } - - @Test - public void fallback_AdsNotWorkingYetTimerExpired() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - - assertNull(childHelper); - assertNull(fallbackHelper1); - - assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1); - - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); - assertNull(childHelper); - assertNotNull(fallbackHelper1); - ArgumentCaptor captor = ArgumentCaptor.forClass(ResolvedAddresses.class); - verify(fallbackBalancer1).handleResolvedAddresses(captor.capture()); - assertThat(captor.getValue().getAttributes().get(ATTR_LOAD_BALANCING_CONFIG)) - .containsExactly("fallback_1_option", "yes"); - - SubchannelPicker picker = mock(SubchannelPicker.class); - fallbackHelper1.updateBalancingState(CONNECTING, picker); - verify(helper).updateBalancingState(CONNECTING, picker); - } - - @Test - public void allDropCancelsFallbackTimer() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - DiscoveryResponse edsResponse = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .setLoadBalancingWeight(UInt32Value.of(1))) - .setPolicy(Policy.newBuilder() - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("throttle") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(100).setDenominator(DenominatorType.HUNDRED).build()) - .build())) - .build())) - .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") - .build(); - serverResponseWriter.onNext(edsResponse); - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); - assertNotNull(childHelper); - assertNull(fallbackHelper1); - verify(fallbackBalancer1, never()).handleResolvedAddresses(any(ResolvedAddresses.class)); - - } - - @Test - public void allDropExitFallbackMode() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - - // let the fallback timer expire - assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1); - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); - assertNull(childHelper); - assertNotNull(fallbackHelper1); - - // receives EDS response with 100% drop - DiscoveryResponse edsResponse = DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.newBuilder() - .addEndpoints(LocalityLbEndpoints.newBuilder() - .setLocality(localityProto1) - .addLbEndpoints(endpoint11) - .setLoadBalancingWeight(UInt32Value.of(1))) - .setPolicy(Policy.newBuilder() - .addDropOverloads( - io.envoyproxy.envoy.api.v2.ClusterLoadAssignment.Policy.DropOverload - .newBuilder() - .setCategory("throttle") - .setDropPercentage(FractionalPercent.newBuilder() - .setNumerator(100).setDenominator(DenominatorType.HUNDRED).build()) - .build())) - .build())) - .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") - .build(); - serverResponseWriter.onNext(edsResponse); - verify(fallbackBalancer1).shutdown(); - assertNotNull(childHelper); - - ArgumentCaptor subchannelPickerCaptor = - ArgumentCaptor.forClass(SubchannelPicker.class); - verify(helper).updateBalancingState(same(CONNECTING), subchannelPickerCaptor.capture()); - assertThat(subchannelPickerCaptor.getValue().pickSubchannel(mock(PickSubchannelArgs.class)) - .isDrop()).isTrue(); - } - - @Test - public void fallback_ErrorWithoutReceivingEdsResponse() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - - assertNull(childHelper); - assertNull(fallbackHelper1); - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).hasSize(1); - - serverResponseWriter.onError(new Exception("fake error")); - - // goes to fallback-at-startup mode immediately - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); - assertNull(childHelper); - assertNotNull(fallbackHelper1); - // verify fallback balancer is working - ArgumentCaptor captor = ArgumentCaptor.forClass(ResolvedAddresses.class); - verify(fallbackBalancer1).handleResolvedAddresses(captor.capture()); - assertThat(captor.getValue().getAttributes().get(ATTR_LOAD_BALANCING_CONFIG)) - .containsExactly("fallback_1_option", "yes"); - - SubchannelPicker picker = mock(SubchannelPicker.class); - fallbackHelper1.updateBalancingState(CONNECTING, picker); - verify(helper).updateBalancingState(CONNECTING, picker); - } - - @Test - public void fallback_EdsResponseReceivedThenErrorBeforeBackendReady() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - serverResponseWriter.onNext(edsResponse); - assertNotNull(childHelper); - assertNull(fallbackHelper1); - verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); - - serverResponseWriter.onError(new Exception("fake error")); - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).hasSize(1); - // verify fallback balancer is not started - assertNull(fallbackHelper1); - verify(fallbackBalancer1, never()).handleResolvedAddresses(any(ResolvedAddresses.class)); - - SubchannelPicker picker1 = mock(SubchannelPicker.class); - childHelper.updateBalancingState(CONNECTING, picker1); - verify(helper, times(2)).updateBalancingState(CONNECTING, BUFFER_PICKER); - childHelper.updateBalancingState(TRANSIENT_FAILURE, picker1); - verify(helper).updateBalancingState(same(TRANSIENT_FAILURE), isA(ErrorPicker.class)); - - assertThat(fakeClock.forwardTime(10, TimeUnit.SECONDS)).isEqualTo(1); - // verify fallback balancer is working - ArgumentCaptor captor = ArgumentCaptor.forClass(ResolvedAddresses.class); - assertNotNull(fallbackHelper1); - verify(fallbackBalancer1).handleResolvedAddresses(captor.capture()); - assertThat(captor.getValue().getAttributes().get(ATTR_LOAD_BALANCING_CONFIG)) - .containsExactly("fallback_1_option", "yes"); - - SubchannelPicker picker2 = mock(SubchannelPicker.class); - childHelper.updateBalancingState(CONNECTING, picker2); - // verify childHelper no more delegates updateBalancingState to parent helper - verify(helper, times(3)).updateBalancingState( - any(ConnectivityState.class), any(SubchannelPicker.class)); - - SubchannelPicker picker3 = mock(SubchannelPicker.class); - fallbackHelper1.updateBalancingState(CONNECTING, picker3); - verify(helper).updateBalancingState(CONNECTING, picker3); - - SubchannelPicker picker4 = mock(SubchannelPicker.class); - childHelper.updateBalancingState(READY, picker4); - verify(fallbackBalancer1).shutdown(); - verify(helper).updateBalancingState(same(READY), isA(InterLocalityPicker.class)); - } - - @Test - public void fallback_AdsErrorWithActiveSubchannel() throws Exception { - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallback1Attributes()) - .build()); - serverResponseWriter.onNext(edsResponse); - assertNotNull(childHelper); - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).hasSize(1); - assertNull(fallbackHelper1); - verify(helper).updateBalancingState(CONNECTING, BUFFER_PICKER); - - childHelper.updateBalancingState(READY, mock(SubchannelPicker.class)); - verify(helper).updateBalancingState(same(READY), isA(InterLocalityPicker.class)); - assertThat(fakeClock.getPendingTasks(fallbackTaskFilter)).isEmpty(); - - serverResponseWriter.onError(new Exception("fake error")); - assertNull(fallbackHelper1); - verify(fallbackBalancer1, never()).handleResolvedAddresses( - any(ResolvedAddresses.class)); - - // verify childHelper still delegates updateBalancingState to parent helper - childHelper.updateBalancingState(CONNECTING, mock(SubchannelPicker.class)); - verify(helper, times(2)).updateBalancingState(CONNECTING, BUFFER_PICKER); - } - - private static Attributes standardModeWithFallback1Attributes() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"fallbackPolicy\" : [{\"fallback_1\" : { \"fallback_1_option\" : \"yes\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - return Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - } - - @Test - public void shutdown_cleanupTimers() throws Exception { - String lbConfigRaw = "{ " - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"unsupported\" : {\"key\" : \"val\"}}, {\"unsupported_2\" : {}}]," - + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"fallback_1\" : {\"key\" : \"val\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - Attributes attrs = Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - lb.handleResolvedAddresses( - ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(attrs) - .build()); - - assertThat(fakeClock.getPendingTasks()).isNotEmpty(); - lb.shutdown(); - assertThat(fakeClock.getPendingTasks()).isEmpty(); - } -} diff --git a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerWithLrsTest.java b/xds/src/test/java/io/grpc/xds/XdsLoadBalancerWithLrsTest.java deleted file mode 100644 index 82e1668b252..00000000000 --- a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerWithLrsTest.java +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds; - -import static com.google.common.truth.Truth.assertThat; -import static io.grpc.LoadBalancer.ATTR_LOAD_BALANCING_CONFIG; -import static org.mockito.AdditionalAnswers.delegatesTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.same; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -import com.google.protobuf.Any; -import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; -import io.envoyproxy.envoy.api.v2.DiscoveryRequest; -import io.envoyproxy.envoy.api.v2.DiscoveryResponse; -import io.envoyproxy.envoy.service.discovery.v2.AggregatedDiscoveryServiceGrpc.AggregatedDiscoveryServiceImplBase; -import io.grpc.Attributes; -import io.grpc.ChannelLogger; -import io.grpc.EquivalentAddressGroup; -import io.grpc.LoadBalancer; -import io.grpc.LoadBalancer.Helper; -import io.grpc.LoadBalancer.ResolvedAddresses; -import io.grpc.LoadBalancerProvider; -import io.grpc.LoadBalancerRegistry; -import io.grpc.ManagedChannel; -import io.grpc.Status; -import io.grpc.Status.Code; -import io.grpc.SynchronizationContext; -import io.grpc.inprocess.InProcessChannelBuilder; -import io.grpc.inprocess.InProcessServerBuilder; -import io.grpc.internal.BackoffPolicy; -import io.grpc.internal.FakeClock; -import io.grpc.internal.JsonParser; -import io.grpc.internal.testing.StreamRecorder; -import io.grpc.stub.StreamObserver; -import io.grpc.testing.GrpcCleanupRule; -import io.grpc.xds.LoadReportClient.LoadReportCallback; -import io.grpc.xds.LoadReportClientImpl.LoadReportClientFactory; -import io.grpc.xds.XdsLoadBalancer.FallbackManager; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.TimeUnit; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.ArgumentCaptor; -import org.mockito.InOrder; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** - * Unit tests for {@link XdsLoadBalancer}, especially for interactions between - * {@link XdsLoadBalancer} and {@link LoadReportClient}. - */ -@RunWith(JUnit4.class) -public class XdsLoadBalancerWithLrsTest { - private static final String SERVICE_AUTHORITY = "test authority"; - - @Rule - public final GrpcCleanupRule cleanupRule = new GrpcCleanupRule(); - - private final SynchronizationContext syncContext = new SynchronizationContext( - new Thread.UncaughtExceptionHandler() { - @Override - public void uncaughtException(Thread t, Throwable e) { - throw new AssertionError(e); - } - }); - - @Mock - private Helper helper; - @Mock - private BackoffPolicy.Provider backoffPolicyProvider; - @Mock - private LocalityStore localityStore; - @Mock - private LoadReportClientFactory lrsClientFactory; - @Mock - private LoadReportClient lrsClient; - @Mock - private LoadStatsStore loadStatsStore; - @Mock - private LoadBalancer fallbackBalancer; - @Mock - private LoadBalancer mockBalancer; - - private final FakeClock fakeClock = new FakeClock(); - private final LoadBalancerRegistry lbRegistry = new LoadBalancerRegistry(); - private final StreamRecorder streamRecorder = StreamRecorder.create(); - private final LoadBalancerProvider fallBackLbProvider = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return "fallback"; - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - fallBackLbHelper = helper; - return fallbackBalancer; - } - }; - private final LoadBalancerProvider lbProvider = new LoadBalancerProvider() { - @Override - public boolean isAvailable() { - return true; - } - - @Override - public int getPriority() { - return 5; - } - - @Override - public String getPolicyName() { - return "supported"; - } - - @Override - public LoadBalancer newLoadBalancer(Helper helper) { - return mockBalancer; - } - }; - - private Helper fallBackLbHelper; - private StreamObserver serverResponseWriter; - private ManagedChannel oobChannel1; - private ManagedChannel oobChannel2; - private ManagedChannel oobChannel3; - private LoadBalancer xdsLoadBalancer; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - String serverName = InProcessServerBuilder.generateName(); - AggregatedDiscoveryServiceImplBase serviceImpl = new AggregatedDiscoveryServiceImplBase() { - @Override - public StreamObserver streamAggregatedResources( - final StreamObserver responseObserver) { - serverResponseWriter = responseObserver; - - return new StreamObserver() { - - @Override - public void onNext(DiscoveryRequest value) { - streamRecorder.onNext(value); - } - - @Override - public void onError(Throwable t) { - streamRecorder.onError(t); - } - - @Override - public void onCompleted() { - streamRecorder.onCompleted(); - responseObserver.onCompleted(); - } - }; - } - }; - cleanupRule.register( - InProcessServerBuilder - .forName(serverName) - .directExecutor() - .addService(serviceImpl) - .build() - .start()); - - InProcessChannelBuilder channelBuilder = - InProcessChannelBuilder.forName(serverName).directExecutor(); - oobChannel1 = mock( - ManagedChannel.class, - delegatesTo(cleanupRule.register(channelBuilder.build()))); - oobChannel2 = mock( - ManagedChannel.class, - delegatesTo(cleanupRule.register(channelBuilder.build()))); - oobChannel3 = mock( - ManagedChannel.class, - delegatesTo(cleanupRule.register(channelBuilder.build()))); - - lbRegistry.register(fallBackLbProvider); - lbRegistry.register(lbProvider); - when(helper.getSynchronizationContext()).thenReturn(syncContext); - when(helper.getScheduledExecutorService()).thenReturn(fakeClock.getScheduledExecutorService()); - when(helper.getAuthority()).thenReturn(SERVICE_AUTHORITY); - when(helper.getChannelLogger()).thenReturn(mock(ChannelLogger.class)); - when(helper.createResolvingOobChannel(anyString())) - .thenReturn(oobChannel1, oobChannel2, oobChannel3); - when(localityStore.getLoadStatsStore()).thenReturn(loadStatsStore); - when(lrsClientFactory.createLoadReportClient(any(ManagedChannel.class), any(Helper.class), - any(BackoffPolicy.Provider.class), any(LoadStatsStore.class))).thenReturn(lrsClient); - - xdsLoadBalancer = - new XdsLoadBalancer(helper, lbRegistry, backoffPolicyProvider, lrsClientFactory, - new FallbackManager(helper, lbRegistry), localityStore); - } - - @After - public void tearDown() { - xdsLoadBalancer.shutdown(); - } - - /** - * Tests load reporting is initiated after receiving the first valid EDS response from the traffic - * director, then its operation is independent of load balancing until xDS load balancer is - * shutdown. - */ - @Test - public void reportLoadAfterReceivingFirstEdsResponseUntilShutdown() throws Exception { - xdsLoadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallbackAttributes()) - .build()); - - verify(lrsClientFactory) - .createLoadReportClient(same(oobChannel1), same(helper), same(backoffPolicyProvider), - same(loadStatsStore)); - assertThat(streamRecorder.getValues()).hasSize(1); - - // Let fallback timer elapse and xDS load balancer enters fallback mode on startup. - assertThat(fakeClock.getPendingTasks()).hasSize(1); - assertThat(fallBackLbHelper).isNull(); - fakeClock.forwardTime(10, TimeUnit.SECONDS); - assertThat(fallBackLbHelper).isNotNull(); - - verify(lrsClient, never()).startLoadReporting(any(LoadReportCallback.class)); - - // Simulates a syntactically incorrect EDS response. - serverResponseWriter.onNext(DiscoveryResponse.getDefaultInstance()); - verify(lrsClient, never()).startLoadReporting(any(LoadReportCallback.class)); - - ArgumentCaptor lrsCallbackCaptor = ArgumentCaptor.forClass(null); - - // Simulate a syntactically correct EDS response. - DiscoveryResponse edsResponse = - DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.getDefaultInstance())) - .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") - .build(); - serverResponseWriter.onNext(edsResponse); - verify(lrsClient).startLoadReporting(lrsCallbackCaptor.capture()); - lrsCallbackCaptor.getValue().onReportResponse(19543); - verify(localityStore).updateOobMetricsReportInterval(19543); - - // Simulate another EDS response from the same remote balancer. - serverResponseWriter.onNext(edsResponse); - - // Simulate an EDS error response. - serverResponseWriter.onError(Status.ABORTED.asException()); - - // Shutdown xDS load balancer. - xdsLoadBalancer.shutdown(); - verify(lrsClient).stopLoadReporting(); - - verifyNoMoreInteractions(lrsClientFactory, lrsClient); - } - - /** - * Tests load report client sends load to new traffic director when xDS load balancer talks to - * the remote balancer. - */ - @Test - @SuppressWarnings("unchecked") - public void reportLoadToNewTrafficDirectorAfterBalancerNameChange() throws Exception { - InOrder inOrder = inOrder(lrsClientFactory, lrsClient); - xdsLoadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallbackAttributes()) - .build()); - - inOrder.verify(lrsClientFactory) - .createLoadReportClient(same(oobChannel1), same(helper), same(backoffPolicyProvider), - same(loadStatsStore)); - assertThat(streamRecorder.getValues()).hasSize(1); - inOrder.verify(lrsClient, never()).startLoadReporting(any(LoadReportCallback.class)); - - // Simulate receiving a new service config with balancer name changed before xDS protocol is - // established. - Map newLbConfig = - (Map) JsonParser.parse( - "{\"balancerName\" : \"dns:///another.balancer.example.com:8080\"," - + "\"fallbackPolicy\" : [{\"fallback\" : { \"fallback_option\" : \"yes\"}}]}"); - - xdsLoadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, newLbConfig).build()) - .build()); - - assertThat(oobChannel1.isShutdown()).isTrue(); - assertThat(streamRecorder.getValues()).hasSize(2); - inOrder.verify(lrsClientFactory) - .createLoadReportClient(same(oobChannel2), same(helper), same(backoffPolicyProvider), - same(loadStatsStore)); - - // Simulate a syntactically correct EDS response. - DiscoveryResponse edsResponse = - DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.getDefaultInstance())) - .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") - .build(); - serverResponseWriter.onNext(edsResponse); - inOrder.verify(lrsClient).startLoadReporting(any(LoadReportCallback.class)); - - // Simulate receiving a new service config with balancer name changed. - newLbConfig = (Map) JsonParser.parse( - "{\"balancerName\" : \"dns:///third.balancer.example.com:8080\"," - + "\"fallbackPolicy\" : [{\"fallback\" : { \"fallback_option\" : \"yes\"}}]}"); - - xdsLoadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, newLbConfig).build()) - .build()); - - assertThat(oobChannel2.isShutdown()).isTrue(); - assertThat(streamRecorder.getValues()).hasSize(3); - inOrder.verify(lrsClient).stopLoadReporting(); - inOrder.verify(lrsClientFactory) - .createLoadReportClient(same(oobChannel3), same(helper), same(backoffPolicyProvider), - same(loadStatsStore)); - - serverResponseWriter.onNext(edsResponse); - inOrder.verify(lrsClient).startLoadReporting(any(LoadReportCallback.class)); - - inOrder.verifyNoMoreInteractions(); - } - - /** - * Tests the case that load reporting is not interrupted when child balancing policy changes, - * even though xDS balancer refreshes discovery RPC with the traffic director. - */ - @Test - public void loadReportNotAffectedWhenChildPolicyChanges() throws Exception { - xdsLoadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(standardModeWithFallbackAttributes()) - .build()); - - verify(lrsClientFactory) - .createLoadReportClient(same(oobChannel1), same(helper), same(backoffPolicyProvider), - same(loadStatsStore)); - assertThat(streamRecorder.getValues()).hasSize(1); - - // Simulate a syntactically correct EDS response. - DiscoveryResponse edsResponse = - DiscoveryResponse.newBuilder() - .addResources(Any.pack(ClusterLoadAssignment.getDefaultInstance())) - .setTypeUrl("type.googleapis.com/envoy.api.v2.ClusterLoadAssignment") - .build(); - serverResponseWriter.onNext(edsResponse); - verify(lrsClient).startLoadReporting(any(LoadReportCallback.class)); - - // Simulate receiving a new service config with child policy changed. - @SuppressWarnings("unchecked") - Map newLbConfig = - (Map) JsonParser.parse( - "{\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"childPolicy\" : [{\"supported\" : {\"key\" : \"val\"}}]," - + "\"fallbackPolicy\" : [{\"fallback\" : { \"fallback_option\" : \"yes\"}}]}"); - - xdsLoadBalancer.handleResolvedAddresses(ResolvedAddresses.newBuilder() - .setAddresses(Collections.emptyList()) - .setAttributes(Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, newLbConfig).build()) - .build()); - - assertThat(oobChannel1.isShutdown()).isFalse(); - assertThat(Status.fromThrowable(streamRecorder.getError()).getCode()) - .isEqualTo(Code.CANCELLED); - assertThat(streamRecorder.getValues()).hasSize(2); - verify(lrsClient, never()).stopLoadReporting(); - - verifyNoMoreInteractions(lrsClientFactory, lrsClient); - } - - private static Attributes standardModeWithFallbackAttributes() throws Exception { - String lbConfigRaw = "{" - + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," - + "\"fallbackPolicy\" : [{\"fallback\" : { \"fallback_option\" : \"yes\"}}]" - + "}"; - @SuppressWarnings("unchecked") - Map lbConfig = (Map) JsonParser.parse(lbConfigRaw); - return Attributes.newBuilder().set(ATTR_LOAD_BALANCING_CONFIG, lbConfig).build(); - } -} From 103c2f9858bb36ece88c9141850ccd1b66f9a4d9 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Thu, 3 Oct 2019 15:37:51 -0700 Subject: [PATCH 064/131] re-add the grpc-netty dependency --- xds/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/xds/build.gradle b/xds/build.gradle index d7fe0ba564a..d69fdc9da6b 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -22,6 +22,7 @@ dependencies { compile project(':grpc-protobuf'), project(':grpc-stub'), project(':grpc-core'), + project(':grpc-netty'), project(':grpc-services') compile (libraries.pgv) { From c16b104e61329946339d303bd21fae19f0698981 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 4 Oct 2019 08:49:49 -0700 Subject: [PATCH 065/131] Adding more attributes to XdsAttributes and making XdsAttributes public to prepare for using *TlsContext in the new SecretManager --- .../main/java/io/grpc/xds/XdsAttributes.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsAttributes.java b/xds/src/main/java/io/grpc/xds/XdsAttributes.java index 20ba4eb3196..9aa870c31a8 100644 --- a/xds/src/main/java/io/grpc/xds/XdsAttributes.java +++ b/xds/src/main/java/io/grpc/xds/XdsAttributes.java @@ -17,15 +17,18 @@ package io.grpc.xds; import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.auth.CommonTlsContext; +import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext; import io.envoyproxy.envoy.api.v2.auth.SdsSecretConfig; import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext; import io.grpc.Attributes; import io.grpc.Grpc; /** * Special attributes that are only useful to gRPC in the XDS context. */ -final class XdsAttributes { +public final class XdsAttributes { /** * Attribute key for SdsSecretConfig of a subchannel. */ @@ -47,5 +50,26 @@ final class XdsAttributes { public static final Attributes.Key ATTR_CERT_VALIDATION_CONTEXT = Attributes.Key.create("io.grpc.xds.XdsAttributes.certificateValidationContext"); + /** + * Attribute key for CommonTlsContext. + */ + @Grpc.TransportAttr + public static final Attributes.Key ATTR_COMMON_TLS_CONTEXT = + Attributes.Key.create("io.grpc.xds.XdsAttributes.commonTlsContext"); + + /** + * Attribute key for UpstreamTlsContext (used by client) for subchannel. + */ + @Grpc.TransportAttr + public static final Attributes.Key ATTR_UPSTREAM_TLS_CONTEXT = + Attributes.Key.create("io.grpc.xds.XdsAttributes.upstreamTlsContext"); + + /** + * Attribute key for DownstreamTlsContext (used by server). + */ + @Grpc.TransportAttr + public static final Attributes.Key ATTR_DOWNSTREAM_TLS_CONTEXT = + Attributes.Key.create("io.grpc.xds.XdsAttributes.downstreamTlsContext"); + private XdsAttributes() {} } From ed4f1fbdae82e53a18cfacb69a2f119346d1855f Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 4 Oct 2019 09:25:58 -0700 Subject: [PATCH 066/131] Mark XdsAttributes internal --- xds/src/main/java/io/grpc/xds/XdsAttributes.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xds/src/main/java/io/grpc/xds/XdsAttributes.java b/xds/src/main/java/io/grpc/xds/XdsAttributes.java index 9aa870c31a8..146d6808442 100644 --- a/xds/src/main/java/io/grpc/xds/XdsAttributes.java +++ b/xds/src/main/java/io/grpc/xds/XdsAttributes.java @@ -24,10 +24,12 @@ import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext; import io.grpc.Attributes; import io.grpc.Grpc; +import io.grpc.Internal; /** * Special attributes that are only useful to gRPC in the XDS context. */ +@Internal public final class XdsAttributes { /** * Attribute key for SdsSecretConfig of a subchannel. From 31b1da5a8d4503881449a6395c236aca55b7422f Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Fri, 4 Oct 2019 12:13:48 -0700 Subject: [PATCH 067/131] xds: bootstrap xDS load balancer with xDS name resolver `XdsNameResolver` will load bootstrap file and populate `Node` reference to the `XdsLoadBalancer` through attributes of `ResolvedAddresses`. This is only for demo purpose until `XdsClient` is available, whence `XdsNameResolver` will populate `XdsClient` reference to `XdsLoadBalancer` through attributes instead. --- .../java/io/grpc/xds/LookasideChannelLb.java | 11 ++-- .../main/java/io/grpc/xds/LookasideLb.java | 29 +++++++-- xds/src/main/java/io/grpc/xds/XdsComms2.java | 14 ++--- .../java/io/grpc/xds/XdsNameResolver.java | 49 ++++++++++++++- .../io/grpc/xds/LookasideChannelLbTest.java | 4 +- .../java/io/grpc/xds/LookasideLbTest.java | 5 +- .../test/java/io/grpc/xds/XdsCommsTest.java | 6 +- .../java/io/grpc/xds/XdsNamResolverTest.java | 59 +++++++++++++++++-- 8 files changed, 148 insertions(+), 29 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java index 37947bbb87e..03821b4fe6e 100644 --- a/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java +++ b/xds/src/main/java/io/grpc/xds/LookasideChannelLb.java @@ -22,6 +22,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; +import io.envoyproxy.envoy.api.v2.core.Node; import io.envoyproxy.envoy.api.v2.endpoint.LocalityLbEndpoints; import io.envoyproxy.envoy.type.FractionalPercent; import io.envoyproxy.envoy.type.FractionalPercent.DenominatorType; @@ -52,7 +53,7 @@ final class LookasideChannelLb extends LoadBalancer { LookasideChannelLb( Helper helper, LookasideChannelCallback lookasideChannelCallback, ManagedChannel lbChannel, - LocalityStore localityStore) { + LocalityStore localityStore, Node node) { this( helper, lookasideChannelCallback, @@ -60,7 +61,8 @@ final class LookasideChannelLb extends LoadBalancer { new LoadReportClientImpl( lbChannel, helper, GrpcUtil.STOPWATCH_SUPPLIER, new ExponentialBackoffPolicy.Provider(), localityStore.getLoadStatsStore()), - localityStore); + localityStore, + node); } @VisibleForTesting @@ -69,7 +71,8 @@ final class LookasideChannelLb extends LoadBalancer { LookasideChannelCallback lookasideChannelCallback, ManagedChannel lbChannel, LoadReportClient lrsClient, - final LocalityStore localityStore) { + final LocalityStore localityStore, + Node node) { this.lbChannel = lbChannel; LoadReportCallback lrsCallback = new LoadReportCallback() { @@ -84,7 +87,7 @@ public void onReportResponse(long reportIntervalNano) { lookasideChannelCallback, lrsClient, lrsCallback, localityStore) ; xdsComms2 = new XdsComms2( lbChannel, helper, adsCallback, new ExponentialBackoffPolicy.Provider(), - GrpcUtil.STOPWATCH_SUPPLIER); + GrpcUtil.STOPWATCH_SUPPLIER, node); } private static int rateInMillion(FractionalPercent fractionalPercent) { diff --git a/xds/src/main/java/io/grpc/xds/LookasideLb.java b/xds/src/main/java/io/grpc/xds/LookasideLb.java index 52570284b30..f29ca897384 100644 --- a/xds/src/main/java/io/grpc/xds/LookasideLb.java +++ b/xds/src/main/java/io/grpc/xds/LookasideLb.java @@ -17,9 +17,13 @@ package io.grpc.xds; import static com.google.common.base.Preconditions.checkNotNull; +import static io.grpc.xds.XdsNameResolver.XDS_NODE; import static java.util.logging.Level.FINEST; import com.google.common.annotations.VisibleForTesting; +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import io.envoyproxy.envoy.api.v2.core.Node; import io.grpc.Attributes; import io.grpc.LoadBalancer; import io.grpc.LoadBalancerProvider; @@ -85,12 +89,22 @@ public void handleResolvedAddresses(ResolvedAddresses resolvedAddresses) { String newBalancerName = xdsConfig.balancerName; if (!newBalancerName.equals(balancerName)) { balancerName = newBalancerName; // cache the name and check next time for optimization - lookasideChannelLb.switchTo(newLookasideChannelLbProvider(newBalancerName)); + Node node = resolvedAddresses.getAttributes().get(XDS_NODE); + if (node == null) { + node = Node.newBuilder() + .setMetadata(Struct.newBuilder() + .putFields( + "endpoints_required", + Value.newBuilder().setBoolValue(true).build())) + .build(); + } + lookasideChannelLb.switchTo(newLookasideChannelLbProvider(newBalancerName, node)); } lookasideChannelLb.handleResolvedAddresses(resolvedAddresses); } - private LoadBalancerProvider newLookasideChannelLbProvider(final String balancerName) { + private LoadBalancerProvider newLookasideChannelLbProvider( + final String balancerName, final Node node) { return new LoadBalancerProvider() { @Override public boolean isAvailable() { @@ -114,7 +128,7 @@ public String getPolicyName() { @Override public LoadBalancer newLoadBalancer(Helper helper) { return lookasideChannelLbFactory.newLoadBalancer( - helper, lookasideChannelCallback, balancerName); + helper, lookasideChannelCallback, balancerName, node); } }; } @@ -122,17 +136,20 @@ public LoadBalancer newLoadBalancer(Helper helper) { @VisibleForTesting interface LookasideChannelLbFactory { LoadBalancer newLoadBalancer( - Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName); + Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName, + Node node); } private static final class LookasideChannelLbFactoryImpl implements LookasideChannelLbFactory { @Override public LoadBalancer newLoadBalancer( - Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName) { + Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName, + Node node) { return new LookasideChannelLb( helper, lookasideChannelCallback, initLbChannel(helper, balancerName), - new LocalityStoreImpl(helper, LoadBalancerRegistry.getDefaultRegistry())); + new LocalityStoreImpl(helper, LoadBalancerRegistry.getDefaultRegistry()), + node); } private static ManagedChannel initLbChannel(Helper helper, String balancerName) { diff --git a/xds/src/main/java/io/grpc/xds/XdsComms2.java b/xds/src/main/java/io/grpc/xds/XdsComms2.java index 5ad18a3b908..d189a9e89c0 100644 --- a/xds/src/main/java/io/grpc/xds/XdsComms2.java +++ b/xds/src/main/java/io/grpc/xds/XdsComms2.java @@ -22,8 +22,6 @@ import com.google.common.base.Stopwatch; import com.google.common.base.Supplier; import com.google.protobuf.InvalidProtocolBufferException; -import com.google.protobuf.Struct; -import com.google.protobuf.Value; import io.envoyproxy.envoy.api.v2.ClusterLoadAssignment; import io.envoyproxy.envoy.api.v2.DiscoveryRequest; import io.envoyproxy.envoy.api.v2.DiscoveryResponse; @@ -49,6 +47,8 @@ final class XdsComms2 { private final Helper helper; private final BackoffPolicy.Provider backoffPolicyProvider; private final Supplier stopwatchSupplier; + // Metadata to be included in every xDS request. + private final Node node; @CheckForNull private ScheduledHandle adsRpcRetryTimer; @@ -177,11 +177,7 @@ public void run() { // Assuming standard mode, and send EDS request only DiscoveryRequest edsRequest = DiscoveryRequest.newBuilder() - .setNode(Node.newBuilder() - .setMetadata(Struct.newBuilder() - .putFields( - "endpoints_required", - Value.newBuilder().setBoolValue(true).build()))) + .setNode(node) .setTypeUrl(EDS_TYPE_URL) // In the future, the right resource name can be obtained from CDS response. .addResourceNames(helper.getAuthority()).build(); @@ -209,10 +205,12 @@ void cancelRpc(String message, Throwable cause) { */ XdsComms2( ManagedChannel channel, Helper helper, AdsStreamCallback adsStreamCallback, - BackoffPolicy.Provider backoffPolicyProvider, Supplier stopwatchSupplier) { + BackoffPolicy.Provider backoffPolicyProvider, Supplier stopwatchSupplier, + Node node) { this.channel = checkNotNull(channel, "channel"); this.helper = checkNotNull(helper, "helper"); this.stopwatchSupplier = checkNotNull(stopwatchSupplier, "stopwatchSupplier"); + this.node = node; this.adsStream = new AdsStream( checkNotNull(adsStreamCallback, "adsStreamCallback")); this.backoffPolicyProvider = checkNotNull(backoffPolicyProvider, "backoffPolicyProvider"); diff --git a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java index f71478570f6..8823eff3c92 100644 --- a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java +++ b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java @@ -18,7 +18,9 @@ import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; +import io.envoyproxy.envoy.api.v2.core.Node; import io.grpc.Attributes; import io.grpc.EquivalentAddressGroup; import io.grpc.NameResolver; @@ -29,6 +31,9 @@ import java.net.URI; import java.util.Collections; import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; /** * A {@link NameResolver} for resolving gRPC target names with "xds-experimental" scheme. @@ -41,6 +46,11 @@ */ final class XdsNameResolver extends NameResolver { + private static final Logger logger = Logger.getLogger(XdsNameResolver.class.getName()); + + @NameResolver.ResolutionResultAttr + static final Attributes.Key XDS_NODE = Attributes.Key.create("xds-node"); + private static final String SERVICE_CONFIG_HARDCODED = "{" + "\"loadBalancingConfig\": [" + "{\"xds_experimental\" : {" @@ -49,13 +59,48 @@ final class XdsNameResolver extends NameResolver { + "]}"; private final String authority; + private final String serviceConfig; + private final Node node; XdsNameResolver(String name) { + this(name, createBootstrapper()); + } + + @VisibleForTesting + XdsNameResolver(String name, @Nullable Bootstrapper bootstrapper) { URI nameUri = URI.create("//" + checkNotNull(name, "name")); Preconditions.checkArgument(nameUri.getHost() != null, "Invalid hostname: %s", name); authority = Preconditions.checkNotNull( nameUri.getAuthority(), "nameUri (%s) doesn't have an authority", nameUri); + + String serviceConfig = SERVICE_CONFIG_HARDCODED; + Node node = Node.getDefaultInstance(); + + if (bootstrapper != null) { + String serverUri = bootstrapper.getServerUri(); + node = bootstrapper.getNode(); + serviceConfig = "{" + + "\"loadBalancingConfig\": [" + + "{\"xds_experimental\" : {" + + "\"balancer_name\" : \"" + serverUri + "\"," + + "\"childPolicy\" : [{\"round_robin\" : {}}]" + + "}}" + + "]}"; + } + + this.serviceConfig = serviceConfig; + this.node = node; + } + + @Nullable + private static Bootstrapper createBootstrapper() { + try { + return Bootstrapper.getInstance(); + } catch (Exception e) { + logger.log(Level.FINE, "Unable to load XDS bootstrap config", e); + } + return null; } @Override @@ -66,9 +111,10 @@ public String getServiceAuthority() { @SuppressWarnings("unchecked") @Override public void start(final Listener2 listener) { + Map config; try { - config = (Map) JsonParser.parse(SERVICE_CONFIG_HARDCODED); + config = (Map) JsonParser.parse(serviceConfig); } catch (IOException e) { listener.onError( Status.UNKNOWN.withDescription("Invalid service config").withCause(e)); @@ -77,6 +123,7 @@ public void start(final Listener2 listener) { Attributes attrs = Attributes.newBuilder() .set(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG, config) + .set(XDS_NODE, node) .build(); ResolutionResult result = ResolutionResult.newBuilder() diff --git a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java index 377eaa4d8f0..b9bee56efbb 100644 --- a/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java +++ b/xds/src/test/java/io/grpc/xds/LookasideChannelLbTest.java @@ -38,6 +38,7 @@ import io.envoyproxy.envoy.api.v2.DiscoveryResponse; import io.envoyproxy.envoy.api.v2.core.Address; import io.envoyproxy.envoy.api.v2.core.Locality; +import io.envoyproxy.envoy.api.v2.core.Node; import io.envoyproxy.envoy.api.v2.core.SocketAddress; import io.envoyproxy.envoy.api.v2.endpoint.Endpoint; import io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint; @@ -169,7 +170,8 @@ public void onCompleted() { doReturn(loadStatsStore).when(localityStore).getLoadStatsStore(); lookasideChannelLb = new LookasideChannelLb( - helper, lookasideChannelCallback, channel, loadReportClient, localityStore); + helper, lookasideChannelCallback, channel, loadReportClient, localityStore, + Node.getDefaultInstance()); } @Test diff --git a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java index dde8eb0cb95..2ad9af4f643 100644 --- a/xds/src/test/java/io/grpc/xds/LookasideLbTest.java +++ b/xds/src/test/java/io/grpc/xds/LookasideLbTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.verify; import com.google.common.collect.ImmutableList; +import io.envoyproxy.envoy.api.v2.core.Node; import io.grpc.Attributes; import io.grpc.EquivalentAddressGroup; import io.grpc.LoadBalancer; @@ -55,11 +56,13 @@ public class LookasideLbTest { new LookasideChannelLbFactory() { @Override public LoadBalancer newLoadBalancer( - Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName) { + Helper helper, LookasideChannelCallback lookasideChannelCallback, String balancerName, + Node node) { // just return a mock and record helper and balancer. helpers.add(helper); LoadBalancer balancer = mock(LoadBalancer.class); balancers.add(balancer); + assertThat(node).isNotNull(); return balancer; } }; diff --git a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java index 1b61655a7e2..07dcc79e77e 100644 --- a/xds/src/test/java/io/grpc/xds/XdsCommsTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsCommsTest.java @@ -37,6 +37,7 @@ import io.envoyproxy.envoy.api.v2.DiscoveryResponse; import io.envoyproxy.envoy.api.v2.core.Address; import io.envoyproxy.envoy.api.v2.core.Locality; +import io.envoyproxy.envoy.api.v2.core.Node; import io.envoyproxy.envoy.api.v2.core.SocketAddress; import io.envoyproxy.envoy.api.v2.endpoint.Endpoint; import io.envoyproxy.envoy.api.v2.endpoint.LbEndpoint; @@ -184,7 +185,7 @@ public LoadBalancer newLoadBalancer(Helper helper) { doReturn(20L, 200L).when(backoffPolicy2).nextBackoffNanos(); xdsComms = new XdsComms2( channel, helper, adsStreamCallback, backoffPolicyProvider, - fakeClock.getStopwatchSupplier()); + fakeClock.getStopwatchSupplier(), Node.getDefaultInstance()); } @Test @@ -207,9 +208,6 @@ public void handleEdsResponse() { assertThat(streamRecorder.getValues()).hasSize(1); DiscoveryRequest request = streamRecorder.getValues().get(0); assertThat(request.getTypeUrl()).isEqualTo(EDS_TYPE_URL); - assertThat( - request.getNode().getMetadata().getFieldsOrThrow("endpoints_required").getBoolValue()) - .isTrue(); assertThat(request.getResourceNamesList()).hasSize(1); Locality localityProto1 = Locality.newBuilder() diff --git a/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java index cc2ea47981e..f22b619a472 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java @@ -17,12 +17,15 @@ package io.grpc.xds; import static com.google.common.truth.Truth.assertThat; +import static io.grpc.xds.XdsNameResolver.XDS_NODE; import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; +import io.envoyproxy.envoy.api.v2.core.Node; import io.grpc.NameResolver; import io.grpc.NameResolver.ResolutionResult; import io.grpc.NameResolver.ServiceConfigParser; @@ -46,6 +49,8 @@ /** Unit tests for {@link XdsNameResolver}. */ @RunWith(JUnit4.class) public class XdsNamResolverTest { + private static final Node FAKE_BOOTSTRAP_NODE = + Node.newBuilder().setBuildVersion("fakeVer").build(); @Rule public final MockitoRule mocks = MockitoJUnit.rule(); @@ -99,17 +104,47 @@ public void invalidName_hostnameContainsUnderscore() { @Test public void resolve_hardcodedResult() { - XdsNameResolver resolver = newResolver("foo.googleapis.com"); + XdsNameResolver resolver = new XdsNameResolver("foo.googleapis.com", null); resolver.start(mockListener); verify(mockListener).onResult(resultCaptor.capture()); assertHardCodedServiceConfig(resultCaptor.getValue()); - resolver = newResolver("bar.googleapis.com"); + resolver = new XdsNameResolver("bar.googleapis.com", null); resolver.start(mockListener); verify(mockListener, times(2)).onResult(resultCaptor.capture()); assertHardCodedServiceConfig(resultCaptor.getValue()); } + @Test + public void resolve_bootstrapResult() { + Bootstrapper bootstrapper = new Bootstrapper() { + @Override + String getServerUri() { + return "fake_server_uri"; + } + + @Override + Node getNode() { + return FAKE_BOOTSTRAP_NODE; + } + + @Override + List getChannelCredentials() { + return ImmutableList.of(); + } + }; + + XdsNameResolver resolver = new XdsNameResolver("foo.googleapis.com", bootstrapper); + resolver.start(mockListener); + verify(mockListener).onResult(resultCaptor.capture()); + assertBootstrapServiceConfig(resultCaptor.getValue()); + + resolver = new XdsNameResolver("bar.googleapis.com", bootstrapper); + resolver.start(mockListener); + verify(mockListener, times(2)).onResult(resultCaptor.capture()); + assertBootstrapServiceConfig(resultCaptor.getValue()); + } + @SuppressWarnings("unchecked") private static void assertHardCodedServiceConfig(ResolutionResult actualResult) { assertThat(actualResult.getAddresses()).isEmpty(); @@ -126,7 +161,23 @@ private static void assertHardCodedServiceConfig(ResolutionResult actualResult) Collections.singletonMap("round_robin", Collections.EMPTY_MAP))); } - private XdsNameResolver newResolver(String name) { - return new XdsNameResolver(name); + @SuppressWarnings("unchecked") + private static void assertBootstrapServiceConfig(ResolutionResult actualResult) { + assertThat(actualResult.getAddresses()).isEmpty(); + Map serviceConfig = + actualResult.getAttributes().get(GrpcAttributes.NAME_RESOLVER_SERVICE_CONFIG); + List> rawLbConfigs = + (List>) serviceConfig.get("loadBalancingConfig"); + Map xdsLbConfig = Iterables.getOnlyElement(rawLbConfigs); + assertThat(xdsLbConfig.keySet()).containsExactly("xds_experimental"); + Map rawConfigValues = (Map) xdsLbConfig.get("xds_experimental"); + assertThat(rawConfigValues) + .containsExactly( + "balancer_name", + "fake_server_uri", + "childPolicy", + Collections.singletonList( + Collections.singletonMap("round_robin", Collections.EMPTY_MAP))); + assertThat(actualResult.getAttributes().get(XDS_NODE)).isEqualTo(FAKE_BOOTSTRAP_NODE); } } From a462a3bc8ecd74590cf438feec5c42323fb4c4cd Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Fri, 4 Oct 2019 15:09:05 -0700 Subject: [PATCH 068/131] COMPILING.md: Reduce dependencies when building protobuf These changes avoid a dependency on automake, autoconf, and libtool. The ./configure script is only available via the release artifacts, not git. For example, on Debian Buster only curl and build-essential need to be installed. --- COMPILING.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/COMPILING.md b/COMPILING.md index 865861f1ceb..23072471e71 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -42,13 +42,12 @@ The codegen plugin is C++ code and requires protobuf 3.0.0 or later. For Linux, Mac and MinGW: ``` -$ git clone https://github.com/google/protobuf.git -$ cd protobuf -$ git checkout v3.9.0 -$ ./autogen.sh +$ PROTOBUF_VERSION=3.9.0 +$ curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOBUF_VERSION/protobuf-all-$PROTOBUF_VERSION.tar.gz +$ tar xzf protobuf-all-$PROTOBUF_VERSION.tar.gz +$ cd protobuf-$PROTOBUF_VERSION $ ./configure --disable-shared -$ make -$ make check +$ make # You may want to pass -j to make this run faster; see make --help $ sudo make install ``` From edd9e5a25726ce8df65e3622e7d083981fb0fcf1 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 4 Oct 2019 10:29:42 -0700 Subject: [PATCH 069/131] define interface for the new TlsContextManager that will replace the SecretManager --- .../io/grpc/xds/sds/TlsContextManager.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java b/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java new file mode 100644 index 00000000000..713435c37fb --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java @@ -0,0 +1,46 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext; +import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext; +import io.grpc.Internal; +import io.netty.handler.ssl.SslContext; + +/** + * Class to manage secrets used to create SSL contexts - this effectively manages SSL contexts + * (aka TlsContexts) based on inputs we get from xDS. This is used by gRPC-xds to access the + * SSL contexts/secrets and is not public API. + * TODO(sanjaypujare): flesh out the implementation and remove the old {@link SecretManager} + * once done. + */ +@Internal +public class TlsContextManager { + + public SecretProvider findOrCreateServerSslContextProvider( + DownstreamTlsContext downstreamTlsContext) { + // TODO(sanjaypujare): implement required SecrerProvider + return null; + } + + public SecretProvider findOrCreateClientSslContextProvider( + UpstreamTlsContext upstreamTlsContext) { + // TODO(sanjaypujare): implement required SecrerProvider + return null; + } + +} From be83a3ddc588bce575a54cfa26d4ce944a877919 Mon Sep 17 00:00:00 2001 From: Sanjay Pujare Date: Fri, 4 Oct 2019 11:21:26 -0700 Subject: [PATCH 070/131] xds: fix Javadoc comments and add final qualifier also fix typo --- .../java/io/grpc/xds/sds/TlsContextManager.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java b/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java index 713435c37fb..5d93a0bfd1a 100644 --- a/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java +++ b/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java @@ -25,22 +25,27 @@ * Class to manage secrets used to create SSL contexts - this effectively manages SSL contexts * (aka TlsContexts) based on inputs we get from xDS. This is used by gRPC-xds to access the * SSL contexts/secrets and is not public API. - * TODO(sanjaypujare): flesh out the implementation and remove the old {@link SecretManager} - * once done. */ @Internal -public class TlsContextManager { +public final class TlsContextManager { + /** + * Finds an existing SecretProvider or creates it if it doesn't exist. + * Used for retrieving a server-side SslContext + */ public SecretProvider findOrCreateServerSslContextProvider( DownstreamTlsContext downstreamTlsContext) { - // TODO(sanjaypujare): implement required SecrerProvider + // TODO(sanjaypujare): implementation of SecretProvider return null; } + /** + * Finds an existing SecretProvider or creates it if it doesn't exist. + * Used for retrieving a client-side SslContext + */ public SecretProvider findOrCreateClientSslContextProvider( UpstreamTlsContext upstreamTlsContext) { - // TODO(sanjaypujare): implement required SecrerProvider + // TODO(sanjaypujare): implementation of SecretProvider return null; } - } From ed220c14b82ba3f1b48a180c8a67564ab78f41e2 Mon Sep 17 00:00:00 2001 From: dapengzhang0 Date: Fri, 4 Oct 2019 18:28:13 -0700 Subject: [PATCH 071/131] xds: fix wrong json key balancerName --- xds/src/main/java/io/grpc/xds/XdsNameResolver.java | 2 +- xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java index 8823eff3c92..9ac6d10e98e 100644 --- a/xds/src/main/java/io/grpc/xds/XdsNameResolver.java +++ b/xds/src/main/java/io/grpc/xds/XdsNameResolver.java @@ -83,7 +83,7 @@ final class XdsNameResolver extends NameResolver { serviceConfig = "{" + "\"loadBalancingConfig\": [" + "{\"xds_experimental\" : {" - + "\"balancer_name\" : \"" + serverUri + "\"," + + "\"balancerName\" : \"" + serverUri + "\"," + "\"childPolicy\" : [{\"round_robin\" : {}}]" + "}}" + "]}"; diff --git a/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java index f22b619a472..02a5cddb671 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java @@ -173,7 +173,7 @@ private static void assertBootstrapServiceConfig(ResolutionResult actualResult) Map rawConfigValues = (Map) xdsLbConfig.get("xds_experimental"); assertThat(rawConfigValues) .containsExactly( - "balancer_name", + "balancerName", "fake_server_uri", "childPolicy", Collections.singletonList( From 5fce838b4e78d8a7b5db9e6b2c2718acd3cafd78 Mon Sep 17 00:00:00 2001 From: dapengzhang0 Date: Fri, 4 Oct 2019 19:05:05 -0700 Subject: [PATCH 072/131] xds: fix wrong class name of XdsNameResolverTest --- .../xds/{XdsNamResolverTest.java => XdsNameResolverTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename xds/src/test/java/io/grpc/xds/{XdsNamResolverTest.java => XdsNameResolverTest.java} (99%) diff --git a/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java similarity index 99% rename from xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java rename to xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java index 02a5cddb671..d92c9c2b288 100644 --- a/xds/src/test/java/io/grpc/xds/XdsNamResolverTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsNameResolverTest.java @@ -48,7 +48,7 @@ /** Unit tests for {@link XdsNameResolver}. */ @RunWith(JUnit4.class) -public class XdsNamResolverTest { +public class XdsNameResolverTest { private static final Node FAKE_BOOTSTRAP_NODE = Node.newBuilder().setBuildVersion("fakeVer").build(); From 764d0b852afab942611a1c1af6c808571e157482 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Mon, 7 Oct 2019 09:34:27 -0700 Subject: [PATCH 073/131] COMPILING.md: we don't need shared lib related steps (#6245) --- COMPILING.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/COMPILING.md b/COMPILING.md index 23072471e71..fdd3a9a7868 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -61,13 +61,6 @@ Protobuf installs to ``/usr/local`` by default. For Visual C++, please refer to the [Protobuf README](https://github.com/google/protobuf/blob/master/cmake/README.md) for how to compile Protobuf. gRPC-java assumes a Release build. -#### Linux and MinGW -If ``/usr/local/lib`` is not in your library search path, you can add it by running: -``` -$ sudo sh -c 'echo /usr/local/lib >> /etc/ld.so.conf' -$ sudo ldconfig -``` - #### Mac Some versions of Mac OS X (e.g., 10.10) doesn't have ``/usr/local`` in the default search paths for header files and libraries. It will fail the build of From f51336f0cc2355a29564a9e6b3a8a2d0cff43e16 Mon Sep 17 00:00:00 2001 From: cmagnuso244 Date: Mon, 7 Oct 2019 10:52:39 -0700 Subject: [PATCH 074/131] examples: Modifies documentation (#6253) --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index a5fa1e1b681..878da521ac1 100644 --- a/examples/README.md +++ b/examples/README.md @@ -91,7 +91,7 @@ before trying out the examples. 1. **[Install gRPC Java library SNAPSHOT locally, including code generation plugin](../COMPILING.md) (Only need this step for non-released versions, e.g. master HEAD).** -2. Run in this directory: +2. From grpc-java/examples directory: ``` $ ./gradlew installDist ``` From e9921b77f2489c012c80daff1ba2738571aea408 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 3 Oct 2019 10:36:37 -0700 Subject: [PATCH 075/131] Create ConscryptLoader for code sharing --- .../grpc/alts/internal/AesGcmAeadCrypter.java | 44 ++-------- .../io/grpc/internal/ConscryptLoader.java | 80 +++++++++++++++++++ .../io/grpc/internal/testing/TestUtils.java | 24 ++---- 3 files changed, 93 insertions(+), 55 deletions(-) create mode 100644 core/src/main/java/io/grpc/internal/ConscryptLoader.java diff --git a/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java b/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java index 3e0bf2f84b4..bd072eab42c 100644 --- a/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java +++ b/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java @@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument; -import java.lang.reflect.Method; +import io.grpc.internal.ConscryptLoader; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.Provider; @@ -111,8 +111,9 @@ static int getKeyLength() { } private static Provider getConscrypt() { - // This is equivalent to if (Conscrypt.isAvailable()) return Conscrypt.newProvider(); - + if (!ConscryptLoader.isPresent()) { + return null; + } // Conscrypt 2.1.0 or later is required. If an older version is used, it will fail with these // sorts of errors: // "The underlying Cipher implementation does not support this method" @@ -120,42 +121,11 @@ private static Provider getConscrypt() { // // While we could use Conscrypt.version() to check compatibility, that is _very_ verbose via // reflection. In practice, old conscrypts are probably not much of a problem. - Class conscryptClass; try { - conscryptClass = Class.forName("org.conscrypt.Conscrypt"); - } catch (ClassNotFoundException ex) { - logger.log(Level.FINE, "Could not find Conscrypt", ex); - return null; - } - Method method; - try { - method = conscryptClass.getMethod("newProvider"); - } catch (SecurityException ex) { - logger.log(Level.FINE, "Could not find Conscrypt factory method", ex); - return null; - } catch (NoSuchMethodException ex) { - logger.log(Level.WARNING, "Could not find Conscrypt factory method", ex); - return null; - } - Object provider; - try { - provider = method.invoke(null); - } catch (IllegalAccessException ex) { - logger.log(Level.WARNING, "Could not call Conscrypt factory method", ex); - return null; - } catch (Throwable ex) { - // This is probably an InvocationTargetException, which means something's wrong with the JNI - // loading. Maybe the platform is not supported. We could have used Conscrypt.isAvailable(), - // but it just catches Throwable as well - logger.log(Level.WARNING, "Failed calling Conscrypt factory method", ex); - return null; - } - if (!(provider instanceof Provider)) { - logger.log( - Level.WARNING, "Could not load Conscrypt. Returned provider was not a Provider: {0}", - provider.getClass().getName()); + return ConscryptLoader.newProvider(); + } catch (Throwable t) { + logger.log(Level.INFO, "Could not load Conscrypt. Will use slower JDK implementation", t); return null; } - return (Provider) provider; } } diff --git a/core/src/main/java/io/grpc/internal/ConscryptLoader.java b/core/src/main/java/io/grpc/internal/ConscryptLoader.java new file mode 100644 index 00000000000..2a0d9e47cee --- /dev/null +++ b/core/src/main/java/io/grpc/internal/ConscryptLoader.java @@ -0,0 +1,80 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.internal; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.Provider; + +/** + * Utility to load dynamically Conscrypt when it is available. + */ +public final class ConscryptLoader { + private static final Method NEW_PROVIDER_METHOD; + private static final Method IS_CONSCRYPT_METHOD; + + static { + Method newProvider; + Method isConscrypt; + try { + Class conscryptClass = Class.forName("org.conscrypt.Conscrypt"); + newProvider = conscryptClass.getMethod("newProvider"); + isConscrypt = conscryptClass.getMethod("isConscrypt", Provider.class); + } catch (ClassNotFoundException ex) { + newProvider = null; + isConscrypt = null; + } catch (NoSuchMethodException ex) { + throw new AssertionError(ex); + } + NEW_PROVIDER_METHOD = newProvider; + IS_CONSCRYPT_METHOD = isConscrypt; + } + + /** + * Returns {@code true} when the Conscrypt Java classes are available. Does not imply it actually + * works on this platform. + */ + public static boolean isPresent() { + return NEW_PROVIDER_METHOD != null; + } + + /** Same as {@code Conscrypt.isConscrypt(Provider)}. */ + public static boolean isConscrypt(Provider provider) { + if (!isPresent()) { + return false; + } + try { + return (Boolean) IS_CONSCRYPT_METHOD.invoke(null, provider); + } catch (IllegalAccessException ex) { + throw new AssertionError(ex); + } catch (InvocationTargetException ex) { + throw new AssertionError(ex); + } + } + + /** Same as {@code Conscrypt.newProvider()}. */ + public static Provider newProvider() throws Throwable { + if (!isPresent()) { + Class.forName("org.conscrypt.Conscrypt"); + throw new AssertionError("Unexpected failure referencing Conscrypt class"); + } + // Exceptions here probably mean something's wrong with the JNI loading. Maybe the platform is + // not supported. It's an error, but it may occur in some environments as part of normal + // operation. It's too hard to distinguish "normal" from "abnormal" failures here. + return (Provider) NEW_PROVIDER_METHOD.invoke(null); + } +} diff --git a/testing/src/main/java/io/grpc/internal/testing/TestUtils.java b/testing/src/main/java/io/grpc/internal/testing/TestUtils.java index f80f6a763ab..6b467eff528 100644 --- a/testing/src/main/java/io/grpc/internal/testing/TestUtils.java +++ b/testing/src/main/java/io/grpc/internal/testing/TestUtils.java @@ -17,6 +17,7 @@ package io.grpc.internal.testing; import com.google.common.base.Throwables; +import io.grpc.internal.ConscryptLoader; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -25,8 +26,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -163,33 +162,22 @@ public static void installConscryptIfAvailable() { conscryptInstallAttempted = true; return; } - Class conscrypt; - try { - conscrypt = Class.forName("org.conscrypt.Conscrypt"); - } catch (ClassNotFoundException ex) { + if (!ConscryptLoader.isPresent()) { conscryptInstallAttempted = true; return; } - Method newProvider; - try { - newProvider = conscrypt.getMethod("newProvider"); - } catch (NoSuchMethodException ex) { - throw new RuntimeException("Could not find newProvider method on Conscrypt", ex); - } Provider provider; try { - provider = (Provider) newProvider.invoke(null); - } catch (IllegalAccessException ex) { - throw new RuntimeException("Could not invoke Conscrypt.newProvider", ex); - } catch (InvocationTargetException ex) { - Throwable root = Throwables.getRootCause(ex); + provider = ConscryptLoader.newProvider(); + } catch (Throwable t) { + Throwable root = Throwables.getRootCause(t); // Conscrypt uses a newer version of glibc than available on RHEL 6 if (root instanceof UnsatisfiedLinkError && root.getMessage() != null && root.getMessage().contains("GLIBC_2.14")) { conscryptInstallAttempted = true; return; } - throw new RuntimeException("Could not invoke Conscrypt.newProvider", ex); + throw new RuntimeException("Could not create Conscrypt provider", t); } Security.addProvider(provider); conscryptInstallAttempted = true; From 2caa77d48f86cd099c8799f8f8df7dfc8992021b Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 3 Oct 2019 10:37:17 -0700 Subject: [PATCH 076/131] netty: Implicitly enable Conscrypt when it is available This implicit loading is more conservative than the loading for tcnative, as Conscrypt will only be implicitly loaded if there are no other options. This means the Java 9+ JSSE is preferred over Conscrypt without explicit user configuration. While we would generally prefer Conscrypt over JSSE, we want to allow the user to configure their security providers. There wasn't a good way to do that with netty-tcnative and the performance of JSSE at the time was abysmal. While generally being a good way to allow adopting Conscrypt, this also allows easily using App Engine Java 8's provided Conscrypt which can substantially reduce binary size. See googleapis/google-cloud-java#6425 --- .../java/io/grpc/netty/GrpcSslContexts.java | 67 ++++++++----------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java index abf35236f02..1b1820d8c1d 100644 --- a/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java +++ b/netty/src/main/java/io/grpc/netty/GrpcSslContexts.java @@ -18,9 +18,9 @@ import static com.google.common.base.Preconditions.checkArgument; -import com.google.common.base.Throwables; import com.google.errorprone.annotations.CanIgnoreReturnValue; import io.grpc.ExperimentalApi; +import io.grpc.internal.ConscryptLoader; import io.netty.handler.codec.http2.Http2SecurityUtil; import io.netty.handler.ssl.ApplicationProtocolConfig; import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; @@ -32,8 +32,6 @@ import io.netty.handler.ssl.SupportedCipherSuiteFilter; import java.io.File; import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.security.Provider; import java.security.Security; import java.util.Arrays; @@ -95,20 +93,6 @@ private GrpcSslContexts() {} NEXT_PROTOCOL_VERSIONS); private static final String SUN_PROVIDER_NAME = "SunJSSE"; - private static final Method IS_CONSCRYPT_PROVIDER; - - static { - Method method = null; - try { - Class conscryptClass = Class.forName("org.conscrypt.Conscrypt"); - method = conscryptClass.getMethod("isConscrypt", Provider.class); - } catch (ClassNotFoundException ex) { - logger.log(Level.FINE, "Conscrypt class not found. Not using Conscrypt", ex); - } catch (NoSuchMethodException ex) { - throw new AssertionError(ex); - } - IS_CONSCRYPT_PROVIDER = method; - } /** * Creates an SslContextBuilder with ciphers and APN appropriate for gRPC. @@ -223,9 +207,9 @@ public static SslContextBuilder configure(SslContextBuilder builder, Provider jd apc = ALPN; } else { throw new IllegalArgumentException( - SUN_PROVIDER_NAME + " selected, but Jetty NPN/ALPN unavailable"); + SUN_PROVIDER_NAME + " selected, but Java 9+ and Jetty NPN/ALPN unavailable"); } - } else if (isConscrypt(jdkProvider)) { + } else if (ConscryptLoader.isConscrypt(jdkProvider)) { apc = ALPN; } else { throw new IllegalArgumentException("Unknown provider; can't configure: " + jdkProvider); @@ -250,9 +234,11 @@ private static SslProvider defaultSslProvider() { logger.log(Level.FINE, "Selecting JDK with provider {0}", provider); return SslProvider.JDK; } + logger.log(Level.INFO, "Java 9 ALPN API unavailable (this may be normal)"); logger.log(Level.INFO, "netty-tcnative unavailable (this may be normal)", OpenSsl.unavailabilityCause()); - logger.log(Level.INFO, "Conscrypt not found (this may be normal)"); + logger.log(Level.INFO, "Conscrypt not found (this may be normal)", + ConscryptHolder.UNAVAILABILITY_CAUSE); logger.log(Level.INFO, "Jetty ALPN unavailable (this may be normal)", JettyTlsUtil.getJettyAlpnUnavailabilityCause()); throw new IllegalStateException( @@ -268,28 +254,14 @@ private static Provider findJdkProvider() { || JettyTlsUtil.isJava9AlpnAvailable()) { return provider; } - } else if (isConscrypt(provider)) { + } else if (ConscryptLoader.isConscrypt(provider)) { return provider; } } - return null; - } - - private static boolean isConscrypt(Provider provider) { - if (IS_CONSCRYPT_PROVIDER == null) { - return false; - } - try { - return (Boolean) IS_CONSCRYPT_PROVIDER.invoke(null, provider); - } catch (IllegalAccessException ex) { - throw new AssertionError(ex); - } catch (InvocationTargetException ex) { - if (ex.getCause() != null) { - Throwables.throwIfUnchecked(ex.getCause()); - // If checked, just wrap up everything. - } - throw new AssertionError(ex); + if (ConscryptHolder.PROVIDER != null) { + return ConscryptHolder.PROVIDER; } + return null; } @SuppressWarnings("deprecation") @@ -304,4 +276,23 @@ static void ensureAlpnAndH2Enabled( HTTP2_VERSION, alpnNegotiator.protocols()); } + + private static class ConscryptHolder { + static final Provider PROVIDER; + static final Throwable UNAVAILABILITY_CAUSE; + + static { + Provider provider; + Throwable cause; + try { + provider = ConscryptLoader.newProvider(); + cause = null; + } catch (Throwable t) { + provider = null; + cause = t; + } + PROVIDER = provider; + UNAVAILABILITY_CAUSE = cause; + } + } } From 0ec31c683e630a794aadbee716d4ac5cc7f4de4e Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Mon, 7 Oct 2019 11:40:20 -0700 Subject: [PATCH 077/131] Revert "Revert "stub: Wait for onClose when blocking stub is interrupted"" (#6255) This reverts commit 0604e14154ce9de8cdb4822100e84d32ac52bf27. --- .../main/java/io/grpc/stub/ClientCalls.java | 79 ++++--- .../java/io/grpc/stub/ClientCallsTest.java | 223 +++++++++++++++++- 2 files changed, 263 insertions(+), 39 deletions(-) diff --git a/stub/src/main/java/io/grpc/stub/ClientCalls.java b/stub/src/main/java/io/grpc/stub/ClientCalls.java index 12adecbd84d..cf770a991e1 100644 --- a/stub/src/main/java/io/grpc/stub/ClientCalls.java +++ b/stub/src/main/java/io/grpc/stub/ClientCalls.java @@ -124,6 +124,7 @@ public static RespT blockingUnaryCall(ClientCall call public static RespT blockingUnaryCall( Channel channel, MethodDescriptor method, CallOptions callOptions, ReqT req) { ThreadlessExecutor executor = new ThreadlessExecutor(); + boolean interrupt = false; ClientCall call = channel.newCall(method, callOptions.withExecutor(executor)); try { ListenableFuture responseFuture = futureUnaryCall(call, req); @@ -131,18 +132,22 @@ public static RespT blockingUnaryCall( try { executor.waitAndDrain(); } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw Status.CANCELLED - .withDescription("Call was interrupted") - .withCause(e) - .asRuntimeException(); + interrupt = true; + call.cancel("Thread interrupted", e); + // Now wait for onClose() to be called, so interceptors can clean up } } return getUnchecked(responseFuture); } catch (RuntimeException e) { + // Something very bad happened. All bets are off; it may be dangerous to wait for onClose(). throw cancelThrow(call, e); } catch (Error e) { + // Something very bad happened. All bets are off; it may be dangerous to wait for onClose(). throw cancelThrow(call, e); + } finally { + if (interrupt) { + Thread.currentThread().interrupt(); + } } } @@ -209,7 +214,7 @@ private static V getUnchecked(Future future) { } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw Status.CANCELLED - .withDescription("Call was interrupted") + .withDescription("Thread interrupted") .withCause(e) .asRuntimeException(); } catch (ExecutionException e) { @@ -553,30 +558,45 @@ ClientCall.Listener listener() { return listener; } - private Object waitForNext() throws InterruptedException { - if (threadless == null) { - return buffer.take(); - } else { - Object next = buffer.poll(); - while (next == null) { - threadless.waitAndDrain(); - next = buffer.poll(); + private Object waitForNext() { + boolean interrupt = false; + try { + if (threadless == null) { + while (true) { + try { + return buffer.take(); + } catch (InterruptedException ie) { + interrupt = true; + call.cancel("Thread interrupted", ie); + // Now wait for onClose() to be called, to guarantee BlockingQueue doesn't fill + } + } + } else { + Object next; + while ((next = buffer.poll()) == null) { + try { + threadless.waitAndDrain(); + } catch (InterruptedException ie) { + interrupt = true; + call.cancel("Thread interrupted", ie); + // Now wait for onClose() to be called, so interceptors can clean up + } + } + return next; + } + } finally { + if (interrupt) { + Thread.currentThread().interrupt(); } - return next; } } @Override public boolean hasNext() { - if (last == null) { - try { - // Will block here indefinitely waiting for content. RPC timeouts defend against permanent - // hangs here as the call will become closed. - last = waitForNext(); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw Status.CANCELLED.withDescription("interrupted").withCause(ie).asRuntimeException(); - } + while (last == null) { + // Will block here indefinitely waiting for content. RPC timeouts defend against permanent + // hangs here as the call will become closed. + last = waitForNext(); } if (last instanceof StatusRuntimeException) { // Rethrow the exception with a new stacktrace. @@ -650,15 +670,14 @@ private static final class ThreadlessExecutor extends ConcurrentLinkedQueue STREAMING_METHOD = + private static final MethodDescriptor UNARY_METHOD = MethodDescriptor.newBuilder() - .setType(MethodDescriptor.MethodType.BIDI_STREAMING) + .setType(MethodDescriptor.MethodType.UNARY) .setFullMethodName("some/method") .setRequestMarshaller(new IntegerMarshaller()) .setResponseMarshaller(new IntegerMarshaller()) .build(); + private static final MethodDescriptor SERVER_STREAMING_METHOD = + UNARY_METHOD.toBuilder().setType(MethodDescriptor.MethodType.SERVER_STREAMING).build(); + private static final MethodDescriptor BIDI_STREAMING_METHOD = + UNARY_METHOD.toBuilder().setType(MethodDescriptor.MethodType.BIDI_STREAMING).build(); private Server server; private ManagedChannel channel; @@ -130,6 +140,69 @@ public void start(io.grpc.ClientCall.Listener listener, Metadata headers } } + @Test + public void blockingUnaryCall2_success() throws Exception { + Integer req = 2; + final Integer resp = 3; + + class BasicUnaryResponse implements UnaryMethod { + Integer request; + + @Override public void invoke(Integer request, StreamObserver responseObserver) { + this.request = request; + responseObserver.onNext(resp); + responseObserver.onCompleted(); + } + } + + BasicUnaryResponse service = new BasicUnaryResponse(); + server = InProcessServerBuilder.forName("simple-reply").directExecutor() + .addService(ServerServiceDefinition.builder("some") + .addMethod(UNARY_METHOD, ServerCalls.asyncUnaryCall(service)) + .build()) + .build().start(); + channel = InProcessChannelBuilder.forName("simple-reply").directExecutor().build(); + Integer actualResponse = + ClientCalls.blockingUnaryCall(channel, UNARY_METHOD, CallOptions.DEFAULT, req); + assertEquals(resp, actualResponse); + assertEquals(req, service.request); + } + + @Test + public void blockingUnaryCall2_interruptedWaitsForOnClose() throws Exception { + Integer req = 2; + + class NoopUnaryMethod implements UnaryMethod { + ServerCallStreamObserver observer; + + @Override public void invoke(Integer request, StreamObserver responseObserver) { + observer = (ServerCallStreamObserver) responseObserver; + } + } + + NoopUnaryMethod methodImpl = new NoopUnaryMethod(); + server = InProcessServerBuilder.forName("noop").directExecutor() + .addService(ServerServiceDefinition.builder("some") + .addMethod(UNARY_METHOD, ServerCalls.asyncUnaryCall(methodImpl)) + .build()) + .build().start(); + + InterruptInterceptor interceptor = new InterruptInterceptor(); + channel = InProcessChannelBuilder.forName("noop") + .directExecutor() + .intercept(interceptor) + .build(); + try { + ClientCalls.blockingUnaryCall(channel, UNARY_METHOD, CallOptions.DEFAULT, req); + fail(); + } catch (StatusRuntimeException ex) { + assertTrue(Thread.interrupted()); + assertTrue("interrupted", ex.getCause() instanceof InterruptedException); + } + assertTrue("onCloseCalled", interceptor.onCloseCalled); + assertTrue("context not cancelled", methodImpl.observer.isCancelled()); + } + @Test public void unaryFutureCallSuccess() throws Exception { final AtomicReference> listener = @@ -372,8 +445,8 @@ public void request(int numMessages) { public void inprocessTransportInboundFlowControl() throws Exception { final Semaphore semaphore = new Semaphore(0); ServerServiceDefinition service = ServerServiceDefinition.builder( - new ServiceDescriptor("some", STREAMING_METHOD)) - .addMethod(STREAMING_METHOD, ServerCalls.asyncBidiStreamingCall( + new ServiceDescriptor("some", BIDI_STREAMING_METHOD)) + .addMethod(BIDI_STREAMING_METHOD, ServerCalls.asyncBidiStreamingCall( new ServerCalls.BidiStreamingMethod() { int iteration; @@ -404,7 +477,7 @@ public void onCompleted() { server = InProcessServerBuilder.forName("go-with-the-flow" + tag).directExecutor() .addService(service).build().start(); channel = InProcessChannelBuilder.forName("go-with-the-flow" + tag).directExecutor().build(); - final ClientCall clientCall = channel.newCall(STREAMING_METHOD, + final ClientCall clientCall = channel.newCall(BIDI_STREAMING_METHOD, CallOptions.DEFAULT); final CountDownLatch latch = new CountDownLatch(1); final List receivedMessages = new ArrayList<>(6); @@ -453,8 +526,8 @@ public void inprocessTransportOutboundFlowControl() throws Exception { final SettableFuture> observerFuture = SettableFuture.create(); ServerServiceDefinition service = ServerServiceDefinition.builder( - new ServiceDescriptor("some", STREAMING_METHOD)) - .addMethod(STREAMING_METHOD, ServerCalls.asyncBidiStreamingCall( + new ServiceDescriptor("some", BIDI_STREAMING_METHOD)) + .addMethod(BIDI_STREAMING_METHOD, ServerCalls.asyncBidiStreamingCall( new ServerCalls.BidiStreamingMethod() { @Override public StreamObserver invoke(StreamObserver responseObserver) { @@ -485,7 +558,7 @@ public void onCompleted() { server = InProcessServerBuilder.forName("go-with-the-flow" + tag).directExecutor() .addService(service).build().start(); channel = InProcessChannelBuilder.forName("go-with-the-flow" + tag).directExecutor().build(); - final ClientCall clientCall = channel.newCall(STREAMING_METHOD, + final ClientCall clientCall = channel.newCall(BIDI_STREAMING_METHOD, CallOptions.DEFAULT); final SettableFuture future = SettableFuture.create(); @@ -564,4 +637,136 @@ public void start(io.grpc.ClientCall.Listener responseListener, Metadata assertSame(trailers, metadata); } } + + @Test + public void blockingServerStreamingCall_interruptedWaitsForOnClose() throws Exception { + Integer req = 2; + + class NoopServerStreamingMethod implements ServerStreamingMethod { + ServerCallStreamObserver observer; + + @Override public void invoke(Integer request, StreamObserver responseObserver) { + observer = (ServerCallStreamObserver) responseObserver; + } + } + + NoopServerStreamingMethod methodImpl = new NoopServerStreamingMethod(); + server = InProcessServerBuilder.forName("noop").directExecutor() + .addService(ServerServiceDefinition.builder("some") + .addMethod(SERVER_STREAMING_METHOD, ServerCalls.asyncServerStreamingCall(methodImpl)) + .build()) + .build().start(); + + InterruptInterceptor interceptor = new InterruptInterceptor(); + channel = InProcessChannelBuilder.forName("noop") + .directExecutor() + .intercept(interceptor) + .build(); + Iterator iter = ClientCalls.blockingServerStreamingCall( + channel.newCall(SERVER_STREAMING_METHOD, CallOptions.DEFAULT), req); + try { + iter.next(); + fail(); + } catch (StatusRuntimeException ex) { + assertTrue(Thread.interrupted()); + assertTrue("interrupted", ex.getCause() instanceof InterruptedException); + } + assertTrue("onCloseCalled", interceptor.onCloseCalled); + assertTrue("context not cancelled", methodImpl.observer.isCancelled()); + } + + @Test + public void blockingServerStreamingCall2_success() throws Exception { + Integer req = 2; + final Integer resp1 = 3; + final Integer resp2 = 4; + + class BasicServerStreamingResponse implements ServerStreamingMethod { + Integer request; + + @Override public void invoke(Integer request, StreamObserver responseObserver) { + this.request = request; + responseObserver.onNext(resp1); + responseObserver.onNext(resp2); + responseObserver.onCompleted(); + } + } + + BasicServerStreamingResponse service = new BasicServerStreamingResponse(); + server = InProcessServerBuilder.forName("simple-reply").directExecutor() + .addService(ServerServiceDefinition.builder("some") + .addMethod(SERVER_STREAMING_METHOD, ServerCalls.asyncServerStreamingCall(service)) + .build()) + .build().start(); + channel = InProcessChannelBuilder.forName("simple-reply").directExecutor().build(); + Iterator iter = ClientCalls.blockingServerStreamingCall( + channel, SERVER_STREAMING_METHOD, CallOptions.DEFAULT, req); + assertEquals(resp1, iter.next()); + assertTrue(iter.hasNext()); + assertEquals(resp2, iter.next()); + assertFalse(iter.hasNext()); + assertEquals(req, service.request); + } + + @Test + public void blockingServerStreamingCall2_interruptedWaitsForOnClose() throws Exception { + Integer req = 2; + + class NoopServerStreamingMethod implements ServerStreamingMethod { + ServerCallStreamObserver observer; + + @Override public void invoke(Integer request, StreamObserver responseObserver) { + observer = (ServerCallStreamObserver) responseObserver; + } + } + + NoopServerStreamingMethod methodImpl = new NoopServerStreamingMethod(); + server = InProcessServerBuilder.forName("noop").directExecutor() + .addService(ServerServiceDefinition.builder("some") + .addMethod(SERVER_STREAMING_METHOD, ServerCalls.asyncServerStreamingCall(methodImpl)) + .build()) + .build().start(); + + InterruptInterceptor interceptor = new InterruptInterceptor(); + channel = InProcessChannelBuilder.forName("noop") + .directExecutor() + .intercept(interceptor) + .build(); + Iterator iter = ClientCalls.blockingServerStreamingCall( + channel, SERVER_STREAMING_METHOD, CallOptions.DEFAULT, req); + try { + iter.next(); + fail(); + } catch (StatusRuntimeException ex) { + assertTrue(Thread.interrupted()); + assertTrue("interrupted", ex.getCause() instanceof InterruptedException); + } + assertTrue("onCloseCalled", interceptor.onCloseCalled); + assertTrue("context not cancelled", methodImpl.observer.isCancelled()); + } + + // Used for blocking tests to check interrupt behavior and make sure onClose is still called. + class InterruptInterceptor implements ClientInterceptor { + boolean onCloseCalled; + + @Override + public ClientCall interceptCall( + MethodDescriptor method, CallOptions callOptions, Channel next) { + return new SimpleForwardingClientCall(next.newCall(method, callOptions)) { + @Override public void start(ClientCall.Listener listener, Metadata headers) { + super.start(new SimpleForwardingClientCallListener(listener) { + @Override public void onClose(Status status, Metadata trailers) { + onCloseCalled = true; + super.onClose(status, trailers); + } + }, headers); + } + + @Override public void halfClose() { + Thread.currentThread().interrupt(); + super.halfClose(); + } + }; + } + } } From 296857b4e7a5bb6b5fe367ca6e9ac401dc134a38 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Tue, 8 Oct 2019 09:27:39 -0700 Subject: [PATCH 078/131] all: remove deprecated usePlaintext(boolean) --- .../io/grpc/ForwardingChannelBuilder.java | 10 --------- .../java/io/grpc/ManagedChannelBuilder.java | 21 ------------------- .../inprocess/InProcessChannelBuilder.java | 11 ---------- .../io/grpc/cronet/CronetChannelBuilder.java | 8 ------- .../io/grpc/netty/NettyChannelBuilder.java | 17 --------------- .../io/grpc/okhttp/OkHttpChannelBuilder.java | 16 -------------- 6 files changed, 83 deletions(-) diff --git a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java index db63180f60d..ab5c3a505b7 100644 --- a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java +++ b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java @@ -95,16 +95,6 @@ public T overrideAuthority(String authority) { return thisT(); } - /** - * @deprecated use {@link #usePlaintext()} instead. - */ - @Override - @Deprecated - public T usePlaintext(boolean skipNegotiation) { - delegate().usePlaintext(skipNegotiation); - return thisT(); - } - @Override public T usePlaintext() { delegate().usePlaintext(); diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index bd07f045b62..7c00cf5dd87 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -150,27 +150,6 @@ public static ManagedChannelBuilder forTarget(String target) { */ public abstract T overrideAuthority(String authority); - /** - * Use of a plaintext connection to the server. By default a secure connection mechanism - * such as TLS will be used. - * - *

    Should only be used for testing or for APIs where the use of such API or the data - * exchanged is not sensitive. - * - * @param skipNegotiation @{code true} if there is a priori knowledge that the endpoint supports - * plaintext, {@code false} if plaintext use must be negotiated. - * @deprecated Use {@link #usePlaintext()} instead. - * - * @throws UnsupportedOperationException if plaintext mode is not supported. - * @return this - * @since 1.0.0 - */ - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1772") - @Deprecated - public T usePlaintext(boolean skipNegotiation) { - throw new UnsupportedOperationException(); - } - /** * Use of a plaintext connection to the server. By default a secure connection mechanism * such as TLS will be used. diff --git a/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java b/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java index 8f8dd42b603..792257758b0 100644 --- a/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java +++ b/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java @@ -94,17 +94,6 @@ public InProcessChannelBuilder useTransportSecurity() { return this; } - /** - * Does nothing. - * - * @deprecated use {@link #usePlaintext()} instead. - */ - @Override - @Deprecated - public InProcessChannelBuilder usePlaintext(boolean skipNegotiation) { - return this; - } - /** * Does nothing. */ diff --git a/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java b/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java index 2fa71220054..1a87de58507 100644 --- a/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java +++ b/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java @@ -127,14 +127,6 @@ public final CronetChannelBuilder alwaysUsePut(boolean enable) { return this; } - /** - * Not supported for building cronet channel. - */ - @Override - public final CronetChannelBuilder usePlaintext(boolean skipNegotiation) { - throw new IllegalArgumentException("Plaintext not currently supported"); - } - /** * Sets {@link android.net.TrafficStats} tag to use when accounting socket traffic caused by this * channel. See {@link android.net.TrafficStats} for more information. If no tag is set (e.g. this diff --git a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java index 84d47b8feee..3b3da720ea0 100644 --- a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java @@ -285,23 +285,6 @@ public NettyChannelBuilder maxInboundMetadataSize(int bytes) { return this; } - /** - * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT} or - * {@code PLAINTEXT_UPGRADE}. - * - * @deprecated use {@link #usePlaintext()} instead. - */ - @Override - @Deprecated - public NettyChannelBuilder usePlaintext(boolean skipNegotiation) { - if (skipNegotiation) { - negotiationType(NegotiationType.PLAINTEXT); - } else { - negotiationType(NegotiationType.PLAINTEXT_UPGRADE); - } - return this; - } - /** * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT}. */ diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java index b8071d9cf62..b5352828f34 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java @@ -305,22 +305,6 @@ public final OkHttpChannelBuilder connectionSpec( return this; } - /** - * Equivalent to using {@link #negotiationType} with {@code PLAINTEXT}. - * - * @deprecated use {@link #usePlaintext()} instead. - */ - @Override - @Deprecated - public final OkHttpChannelBuilder usePlaintext(boolean skipNegotiation) { - if (skipNegotiation) { - negotiationType(io.grpc.okhttp.NegotiationType.PLAINTEXT); - } else { - throw new IllegalArgumentException("Plaintext negotiation not currently supported"); - } - return this; - } - /** Sets the negotiation type for the HTTP/2 connection to plaintext. */ @Override public final OkHttpChannelBuilder usePlaintext() { From b69f19d58901a55be65db507f891d985732ee419 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Tue, 8 Oct 2019 10:06:26 -0700 Subject: [PATCH 079/131] okhttp: add full implementation of HPACK header compression (#6026) This change added the missing implementation of HTTP/2 HPACK for writer. The implementation is copied (and modified) from upstream OkHttp (OkHttp3). - Huffman encoding of writer is disabled by default. --- .../io/grpc/okhttp/internal/framed/Hpack.java | 217 +++++++- .../okhttp/internal/framed/HpackTest.java | 481 ++++++++++++++++-- 2 files changed, 643 insertions(+), 55 deletions(-) diff --git a/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/framed/Hpack.java b/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/framed/Hpack.java index d574e19960c..484cc5673dc 100644 --- a/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/framed/Hpack.java +++ b/okhttp/third_party/okhttp/main/java/io/grpc/okhttp/internal/framed/Hpack.java @@ -26,7 +26,6 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; - import okio.Buffer; import okio.BufferedSource; import okio.ByteString; @@ -48,6 +47,16 @@ final class Hpack { private static final int PREFIX_6_BITS = 0x3f; private static final int PREFIX_7_BITS = 0x7f; + private static final ByteString PSEUDO_PREFIX = ByteString.encodeUtf8(":"); + + private static final int SETTINGS_HEADER_TABLE_SIZE = 4_096; + + /** + * The decoder has ultimate control of the maximum size of the dynamic table but we can choose + * to use less. We'll put a cap at 16K. This is arbitrary but should be enough for most purposes. + */ + private static final int SETTINGS_HEADER_TABLE_SIZE_LIMIT = 16_384; + private static final io.grpc.okhttp.internal.framed.Header[] STATIC_HEADER_TABLE = new io.grpc.okhttp.internal.framed.Header[] { new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_AUTHORITY, ""), new io.grpc.okhttp.internal.framed.Header(io.grpc.okhttp.internal.framed.Header.TARGET_METHOD, "GET"), @@ -131,8 +140,13 @@ static final class Reader { int dynamicTableByteCount = 0; Reader(int headerTableSizeSetting, Source source) { + this(headerTableSizeSetting, headerTableSizeSetting, source); + } + + // Visible for testing. + Reader(int headerTableSizeSetting, int maxDynamicTableByteCount, Source source) { this.headerTableSizeSetting = headerTableSizeSetting; - this.maxDynamicTableByteCount = headerTableSizeSetting; + this.maxDynamicTableByteCount = maxDynamicTableByteCount; this.source = Okio.buffer(source); } @@ -270,11 +284,15 @@ private void readLiteralHeaderWithIncrementalIndexingNewName() throws IOExceptio insertIntoDynamicTable(-1, new io.grpc.okhttp.internal.framed.Header(name, value)); } - private ByteString getName(int index) { + private ByteString getName(int index) throws IOException { if (isStaticHeader(index)) { return STATIC_HEADER_TABLE[index].name; } else { - return dynamicTable[dynamicTableIndex(index - STATIC_HEADER_TABLE.length)].name; + int dynamicTableIndex = dynamicTableIndex(index - STATIC_HEADER_TABLE.length); + if (dynamicTableIndex < 0 || dynamicTableIndex >= dynamicTable.length) { + throw new IOException("Header index too large " + (index + 1)); + } + return dynamicTable[dynamicTableIndex].name; } } @@ -373,26 +391,108 @@ private static Map nameToFirstIndex() { static final class Writer { private final Buffer out; + private boolean useCompression; + // Visible for testing. + int headerTableSizeSetting; + /** + * In the scenario where the dynamic table size changes multiple times between transmission of + * header blocks, we need to keep track of the smallest value in that interval. + */ + private int smallestHeaderTableSizeSetting = Integer.MAX_VALUE; + private boolean emitDynamicTableSizeUpdate; + private int maxDynamicTableByteCount; + + // Visible for testing. + io.grpc.okhttp.internal.framed.Header[] dynamicTable = new io.grpc.okhttp.internal.framed.Header[8]; + // Visible for testing. + int dynamicTableHeaderCount; + + // Array is populated back to front, so new entries always have lowest index. + private int nextDynamicTableIndex = dynamicTable.length - 1; + private int dynamicTableByteCount; + + // Disable Huffman encoding as for the CPU vs bandwidth trade-off. Writer(Buffer out) { + this(SETTINGS_HEADER_TABLE_SIZE, false, out); + } + + // Visible for testing. + Writer(int headerTableSizeSetting, boolean useCompression, Buffer out) { + this.headerTableSizeSetting = headerTableSizeSetting; + this.maxDynamicTableByteCount = headerTableSizeSetting; + this.useCompression = useCompression; this.out = out; } /** This does not use "never indexed" semantics for sensitive headers. */ // http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#section-6.2.3 void writeHeaders(List headerBlock) throws IOException { - // TODO: implement index tracking + if (emitDynamicTableSizeUpdate) { + if (smallestHeaderTableSizeSetting < maxDynamicTableByteCount) { + // Multiple dynamic table size updates! + writeInt(smallestHeaderTableSizeSetting, PREFIX_5_BITS, 0x20); + } + emitDynamicTableSizeUpdate = false; + smallestHeaderTableSizeSetting = Integer.MAX_VALUE; + writeInt(maxDynamicTableByteCount, PREFIX_5_BITS, 0x20); + } + for (int i = 0, size = headerBlock.size(); i < size; i++) { - ByteString name = headerBlock.get(i).name.toAsciiLowercase(); + io.grpc.okhttp.internal.framed.Header header = headerBlock.get(i); + ByteString name = header.name.toAsciiLowercase(); + ByteString value = header.value; + int headerIndex = -1; + int headerNameIndex = -1; + Integer staticIndex = NAME_TO_FIRST_INDEX.get(name); if (staticIndex != null) { - // Literal Header Field without Indexing - Indexed Name. - writeInt(staticIndex + 1, PREFIX_4_BITS, 0); - writeByteString(headerBlock.get(i).value); - } else { - out.writeByte(0x00); // Literal Header without Indexing - New Name. + headerNameIndex = staticIndex + 1; + if (headerNameIndex >= 2 && headerNameIndex <= 7) { + // Only search a subset of the static header table. Most entries have an empty value, so + // it's unnecessary to waste cycles looking at them. This check is built on the + // observation that the header entries we care about are in adjacent pairs, and we + // always know the first index of the pair. + if (STATIC_HEADER_TABLE[headerNameIndex - 1].value.equals(value)) { + headerIndex = headerNameIndex; + } else if (STATIC_HEADER_TABLE[headerNameIndex].value.equals(value)) { + headerIndex = headerNameIndex + 1; + } + } + } + + if (headerIndex == -1) { + for (int j = nextDynamicTableIndex + 1; j < dynamicTable.length; j++) { + if (dynamicTable[j].name.equals(name)) { + if (dynamicTable[j].value.equals(value)) { + headerIndex = j - nextDynamicTableIndex + STATIC_HEADER_TABLE.length; + break; + } else if (headerNameIndex == -1) { + headerNameIndex = j - nextDynamicTableIndex + STATIC_HEADER_TABLE.length; + } + } + } + } + + if (headerIndex != -1) { + // Indexed Header Field. + writeInt(headerIndex, PREFIX_7_BITS, 0x80); + } else if (headerNameIndex == -1) { + // Literal Header Field with Incremental Indexing - New Name. + out.writeByte(0x40); writeByteString(name); - writeByteString(headerBlock.get(i).value); + writeByteString(value); + insertIntoDynamicTable(header); + } else if (name.startsWith(PSEUDO_PREFIX) && !io.grpc.okhttp.internal.framed.Header.TARGET_AUTHORITY.equals(name)) { + // Follow Chromes lead - only include the :authority pseudo header, but exclude all other + // pseudo headers. Literal Header Field without Indexing - Indexed Name. + writeInt(headerNameIndex, PREFIX_4_BITS, 0); + writeByteString(value); + } else { + // Literal Header Field with Incremental Indexing - Indexed Name. + writeInt(headerNameIndex, PREFIX_6_BITS, 0x40); + writeByteString(value); + insertIntoDynamicTable(header); } } } @@ -419,8 +519,97 @@ void writeInt(int value, int prefixMask, int bits) throws IOException { } void writeByteString(ByteString data) throws IOException { - writeInt(data.size(), PREFIX_7_BITS, 0); - out.write(data); + if (useCompression && io.grpc.okhttp.internal.framed.Huffman.get().encodedLength(data.toByteArray()) < data.size()) { + Buffer huffmanBuffer = new Buffer(); + io.grpc.okhttp.internal.framed.Huffman.get().encode(data.toByteArray(), huffmanBuffer.outputStream()); + ByteString huffmanBytes = huffmanBuffer.readByteString(); + writeInt(huffmanBytes.size(), PREFIX_7_BITS, 0x80); + out.write(huffmanBytes); + } else { + writeInt(data.size(), PREFIX_7_BITS, 0); + out.write(data); + } + } + + int maxDynamicTableByteCount() { + return maxDynamicTableByteCount; + } + + private void clearDynamicTable() { + Arrays.fill(dynamicTable, null); + nextDynamicTableIndex = dynamicTable.length - 1; + dynamicTableHeaderCount = 0; + dynamicTableByteCount = 0; + } + + /** Returns the count of entries evicted. */ + private int evictToRecoverBytes(int bytesToRecover) { + int entriesToEvict = 0; + if (bytesToRecover > 0) { + // determine how many headers need to be evicted. + for (int j = dynamicTable.length - 1; j >= nextDynamicTableIndex && bytesToRecover > 0; j--) { + bytesToRecover -= dynamicTable[j].hpackSize; + dynamicTableByteCount -= dynamicTable[j].hpackSize; + dynamicTableHeaderCount--; + entriesToEvict++; + } + System.arraycopy(dynamicTable, nextDynamicTableIndex + 1, dynamicTable, + nextDynamicTableIndex + 1 + entriesToEvict, dynamicTableHeaderCount); + nextDynamicTableIndex += entriesToEvict; + } + return entriesToEvict; + } + + private void insertIntoDynamicTable(io.grpc.okhttp.internal.framed.Header entry) { + int delta = entry.hpackSize; + + // if the new or replacement header is too big, drop all entries. + if (delta > maxDynamicTableByteCount) { + clearDynamicTable(); + return; + } + + // Evict headers to the required length. + int bytesToRecover = dynamicTableByteCount + delta - maxDynamicTableByteCount; + evictToRecoverBytes(bytesToRecover); + + if (dynamicTableHeaderCount + 1 > dynamicTable.length) { // Need to grow the dynamic table. + io.grpc.okhttp.internal.framed.Header[] doubled = new io.grpc.okhttp.internal.framed.Header[dynamicTable.length * 2]; + System.arraycopy(dynamicTable, 0, doubled, dynamicTable.length, dynamicTable.length); + nextDynamicTableIndex = dynamicTable.length - 1; + dynamicTable = doubled; + } + int index = nextDynamicTableIndex--; + dynamicTable[index] = entry; + dynamicTableHeaderCount++; + dynamicTableByteCount += delta; + } + + void resizeHeaderTable(int headerTableSizeSetting) { + this.headerTableSizeSetting = headerTableSizeSetting; + int effectiveHeaderTableSize = Math.min(headerTableSizeSetting, SETTINGS_HEADER_TABLE_SIZE_LIMIT); + + if (maxDynamicTableByteCount == effectiveHeaderTableSize) { // No change. + return; + } + + if (effectiveHeaderTableSize < maxDynamicTableByteCount) { + smallestHeaderTableSizeSetting = + Math.min(smallestHeaderTableSizeSetting, effectiveHeaderTableSize); + } + emitDynamicTableSizeUpdate = true; + maxDynamicTableByteCount = effectiveHeaderTableSize; + adjustDynamicTableByteCount(); + } + + private void adjustDynamicTableByteCount() { + if (maxDynamicTableByteCount < dynamicTableByteCount) { + if (maxDynamicTableByteCount == 0) { + clearDynamicTable(); + } else { + evictToRecoverBytes(dynamicTableByteCount - maxDynamicTableByteCount); + } + } } } diff --git a/okhttp/third_party/okhttp/test/java/io/grpc/okhttp/internal/framed/HpackTest.java b/okhttp/third_party/okhttp/test/java/io/grpc/okhttp/internal/framed/HpackTest.java index 9c919e9fbe9..26580f85e54 100644 --- a/okhttp/third_party/okhttp/test/java/io/grpc/okhttp/internal/framed/HpackTest.java +++ b/okhttp/third_party/okhttp/test/java/io/grpc/okhttp/internal/framed/HpackTest.java @@ -16,9 +16,13 @@ package io.grpc.okhttp.internal.framed; +import static okio.ByteString.decodeHex; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + import java.io.IOException; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import okio.Buffer; import okio.ByteString; @@ -27,10 +31,6 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import static okio.ByteString.decodeHex; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; - @RunWith(JUnit4.class) public class HpackTest { @@ -49,7 +49,7 @@ private static List

    headerEntries(String... elements) { @Before public void reset() { hpackReader = newReader(bytesIn); - hpackWriter = new Hpack.Writer(bytesOut); + hpackWriter = new Hpack.Writer(4096, false, bytesOut); } /** @@ -77,6 +77,7 @@ private static List
    headerEntries(String... elements) { * Ensure the larger header content is not lost. */ @Test public void tooLargeToHPackIsStillEmitted() throws IOException { + bytesIn.writeByte(0x21); // Dynamic table size update (size = 1). bytesIn.writeByte(0x00); // Literal indexed bytesIn.writeByte(0x0a); // Literal name (len = 10) bytesIn.writeUtf8("custom-key"); @@ -109,7 +110,14 @@ private static List
    headerEntries(String... elements) { } /** Oldest entries are evicted to support newer ones. */ - @Test public void testEviction() throws IOException { + @Test + public void writerEviction() throws IOException { + List
    headerBlock = + headerEntries( + "custom-foo", "custom-header", + "custom-bar", "custom-header", + "custom-baz", "custom-header"); + bytesIn.writeByte(0x40); // Literal indexed bytesIn.writeByte(0x0a); // Literal name (len = 10) bytesIn.writeUtf8("custom-foo"); @@ -132,33 +140,84 @@ private static List
    headerEntries(String... elements) { bytesIn.writeUtf8("custom-header"); // Set to only support 110 bytes (enough for 2 headers). - hpackReader.headerTableSizeSetting(110); - hpackReader.readHeaders(); + // Use a new Writer because we don't support change the dynamic table + // size after Writer constructed. + Hpack.Writer writer = new Hpack.Writer(110, false, bytesOut); + writer.writeHeaders(headerBlock); - assertEquals(2, hpackReader.dynamicTableHeaderCount); + assertEquals(bytesIn, bytesOut); + assertEquals(2, writer.dynamicTableHeaderCount); - Header entry = hpackReader.dynamicTable[headerTableLength() - 1]; + int tableLength = writer.dynamicTable.length; + Header entry = writer.dynamicTable[tableLength - 1]; checkEntry(entry, "custom-bar", "custom-header", 55); - entry = hpackReader.dynamicTable[headerTableLength() - 2]; + entry = writer.dynamicTable[tableLength - 2]; checkEntry(entry, "custom-baz", "custom-header", 55); + } - // Once a header field is decoded and added to the reconstructed header - // list, it cannot be removed from it. Hence, foo is here. - assertEquals( + @Test + public void readerEviction() throws IOException { + List
    headerBlock = headerEntries( "custom-foo", "custom-header", "custom-bar", "custom-header", - "custom-baz", "custom-header"), - hpackReader.getAndResetHeaderList()); + "custom-baz", "custom-header"); + + // Set to only support 110 bytes (enough for 2 headers). + bytesIn.writeByte(0x3F); // Dynamic table size update (size = 110). + bytesIn.writeByte(0x4F); + + bytesIn.writeByte(0x40); // Literal indexed + bytesIn.writeByte(0x0a); // Literal name (len = 10) + bytesIn.writeUtf8("custom-foo"); + + bytesIn.writeByte(0x0d); // Literal value (len = 13) + bytesIn.writeUtf8("custom-header"); + + bytesIn.writeByte(0x40); // Literal indexed + bytesIn.writeByte(0x0a); // Literal name (len = 10) + bytesIn.writeUtf8("custom-bar"); + + bytesIn.writeByte(0x0d); // Literal value (len = 13) + bytesIn.writeUtf8("custom-header"); + + bytesIn.writeByte(0x40); // Literal indexed + bytesIn.writeByte(0x0a); // Literal name (len = 10) + bytesIn.writeUtf8("custom-baz"); + + bytesIn.writeByte(0x0d); // Literal value (len = 13) + bytesIn.writeUtf8("custom-header"); + + hpackReader.readHeaders(); + + assertEquals(2, hpackReader.dynamicTableHeaderCount); + + Header entry1 = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; + checkEntry(entry1, "custom-bar", "custom-header", 55); + + Header entry2 = hpackReader.dynamicTable[readerHeaderTableLength() - 2]; + checkEntry(entry2, "custom-baz", "custom-header", 55); + + // Once a header field is decoded and added to the reconstructed header + // list, it cannot be removed from it. Hence, foo is here. + assertEquals(headerBlock, hpackReader.getAndResetHeaderList()); - // Simulate receiving a small settings frame, that implies eviction. - hpackReader.headerTableSizeSetting(55); + // Simulate receiving a small dynamic table size update, that implies eviction. + bytesIn.writeByte(0x3F); // Dynamic table size update (size = 55). + bytesIn.writeByte(0x18); + hpackReader.readHeaders(); assertEquals(1, hpackReader.dynamicTableHeaderCount); } /** Header table backing array is initially 8 long, let's ensure it grows. */ @Test public void dynamicallyGrowsBeyond64Entries() throws IOException { + // Lots of headers need more room! + hpackReader = new Hpack.Reader(16384, 4096, bytesIn); + bytesIn.writeByte(0x3F); // Dynamic table size update (size = 16384). + bytesIn.writeByte(0xE1); + bytesIn.writeByte(0x7F); + for (int i = 0; i < 256; i++) { bytesIn.writeByte(0x40); // Literal indexed bytesIn.writeByte(0x0a); // Literal name (len = 10) @@ -168,7 +227,6 @@ private static List
    headerEntries(String... elements) { bytesIn.writeUtf8("custom-header"); } - hpackReader.headerTableSizeSetting(16384); // Lots of headers need more room! hpackReader.readHeaders(); assertEquals(256, hpackReader.dynamicTableHeaderCount); @@ -186,7 +244,7 @@ private static List
    headerEntries(String... elements) { assertEquals(1, hpackReader.dynamicTableHeaderCount); assertEquals(52, hpackReader.dynamicTableByteCount); - Header entry = hpackReader.dynamicTable[headerTableLength() - 1]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":path", "www.example.com", 52); } @@ -206,7 +264,7 @@ private static List
    headerEntries(String... elements) { assertEquals(1, hpackReader.dynamicTableHeaderCount); assertEquals(55, hpackReader.dynamicTableByteCount); - Header entry = hpackReader.dynamicTable[headerTableLength() - 1]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, "custom-key", "custom-header", 55); assertEquals(headerEntries("custom-key", "custom-header"), hpackReader.getAndResetHeaderList()); @@ -243,9 +301,6 @@ private static List
    headerEntries(String... elements) { bytesIn.writeByte(0x0d); // Literal value (len = 13) bytesIn.writeUtf8("custom-header"); - hpackWriter.writeHeaders(headerBlock); - assertEquals(bytesIn, bytesOut); - hpackReader.readHeaders(); assertEquals(0, hpackReader.dynamicTableHeaderCount); @@ -281,6 +336,78 @@ private static List
    headerEntries(String... elements) { assertEquals(headerEntries("custom-key", "custom-header"), hpackReader.getAndResetHeaderList()); } + @Test + public void literalHeaderFieldWithIncrementalIndexingIndexedName() throws IOException { + List
    headerBlock = headerEntries(":path", "/sample/path"); + + bytesIn.writeByte(0x44); // Indexed name (idx = 4) -> :path + bytesIn.writeByte(0x0c); // Literal value (len = 12) + bytesIn.writeUtf8("/sample/path"); + + hpackReader.readHeaders(); + + assertEquals(1, hpackReader.dynamicTableHeaderCount); + + assertEquals(headerBlock, hpackReader.getAndResetHeaderList()); + } + + @Test + public void literalHeaderFieldWithIncrementalIndexingNewName() throws IOException { + List
    headerBlock = headerEntries("custom-key", "custom-header"); + + bytesIn.writeByte(0x40); // Never indexed + bytesIn.writeByte(0x0a); // Literal name (len = 10) + bytesIn.writeUtf8("custom-key"); + + bytesIn.writeByte(0x0d); // Literal value (len = 13) + bytesIn.writeUtf8("custom-header"); + + hpackWriter.writeHeaders(headerBlock); + assertEquals(bytesIn, bytesOut); + + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + Header entry = hpackWriter.dynamicTable[hpackWriter.dynamicTable.length - 1]; + checkEntry(entry, "custom-key", "custom-header", 55); + + hpackReader.readHeaders(); + + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + assertEquals(headerBlock, hpackReader.getAndResetHeaderList()); + } + + @Test + public void theSameHeaderAfterOneIncrementalIndexed() throws IOException { + List
    headerBlock = + headerEntries( + "custom-key", "custom-header", + "custom-key", "custom-header"); + + bytesIn.writeByte(0x40); // Never indexed + bytesIn.writeByte(0x0a); // Literal name (len = 10) + bytesIn.writeUtf8("custom-key"); + + bytesIn.writeByte(0x0d); // Literal value (len = 13) + bytesIn.writeUtf8("custom-header"); + + bytesIn.writeByte(0xbe); // Indexed name and value (idx = 63) + + hpackWriter.writeHeaders(headerBlock); + assertEquals(bytesIn, bytesOut); + + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + Header entry = hpackWriter.dynamicTable[hpackWriter.dynamicTable.length - 1]; + checkEntry(entry, "custom-key", "custom-header", 55); + + hpackReader.readHeaders(); + + assertEquals(1, hpackReader.dynamicTableHeaderCount); + + assertEquals(headerBlock, hpackReader.getAndResetHeaderList()); + } + @Test public void staticHeaderIsNotCopiedIntoTheIndexedTable() throws IOException { bytesIn.writeByte(0x82); // == Indexed - Add == // idx = 2 -> :method: GET @@ -290,7 +417,7 @@ private static List
    headerEntries(String... elements) { assertEquals(0, hpackReader.dynamicTableHeaderCount); assertEquals(0, hpackReader.dynamicTableByteCount); - assertEquals(null, hpackReader.dynamicTable[headerTableLength() - 1]); + assertEquals(null, hpackReader.dynamicTable[readerHeaderTableLength() - 1]); assertEquals(headerEntries(":method", "GET"), hpackReader.getAndResetHeaderList()); } @@ -378,10 +505,10 @@ private static List
    headerEntries(String... elements) { * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C.2.4 */ @Test public void readIndexedHeaderFieldFromStaticTableWithoutBuffering() throws IOException { + bytesIn.writeByte(0x20); // Dynamic table size update (size = 0). bytesIn.writeByte(0x82); // == Indexed - Add == // idx = 2 -> :method: GET - hpackReader.headerTableSizeSetting(0); // SETTINGS_HEADER_TABLE_SIZE == 0 hpackReader.readHeaders(); // Not buffered in header table. @@ -390,6 +517,38 @@ private static List
    headerEntries(String... elements) { assertEquals(headerEntries(":method", "GET"), hpackReader.getAndResetHeaderList()); } + @Test + public void readLiteralHeaderWithIncrementalIndexingStaticName() throws IOException { + bytesIn.writeByte(0x7d); // == Literal indexed == + // Indexed name (idx = 60) -> "www-authenticate" + bytesIn.writeByte(0x05); // Literal value (len = 5) + bytesIn.writeUtf8("Basic"); + + hpackReader.readHeaders(); + + assertEquals(headerEntries("www-authenticate", "Basic"), + hpackReader.getAndResetHeaderList()); + } + + @Test + public void readLiteralHeaderWithIncrementalIndexingDynamicName() throws IOException { + bytesIn.writeByte(0x40); + bytesIn.writeByte(0x0a); // Literal name (len = 10) + bytesIn.writeUtf8("custom-foo"); + bytesIn.writeByte(0x05); // Literal value (len = 5) + bytesIn.writeUtf8("Basic"); + + bytesIn.writeByte(0x7e); + bytesIn.writeByte(0x06); // Literal value (len = 6) + bytesIn.writeUtf8("Basic2"); + + hpackReader.readHeaders(); + + assertEquals(headerEntries("custom-foo", "Basic", "custom-foo", "Basic2"), + hpackReader.getAndResetHeaderList()); + } + + /** * http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-12#appendix-C.2 */ @@ -407,6 +566,28 @@ private static List
    headerEntries(String... elements) { checkReadThirdRequestWithoutHuffman(); } + @Test + public void readFailingRequestExample() throws IOException { + bytesIn.writeByte(0x82); // == Indexed - Add == + // idx = 2 -> :method: GET + bytesIn.writeByte(0x86); // == Indexed - Add == + // idx = 7 -> :scheme: http + bytesIn.writeByte(0x84); // == Indexed - Add == + + bytesIn.writeByte(0x7f); // == Bad index! == + + // Indexed name (idx = 4) -> :authority + bytesIn.writeByte(0x0f); // Literal value (len = 15) + bytesIn.writeUtf8("www.example.com"); + + try { + hpackReader.readHeaders(); + fail(); + } catch (IOException e) { + assertEquals("Header index too large 78", e.getMessage()); + } + } + private void firstRequestWithoutHuffman() { bytesIn.writeByte(0x82); // == Indexed - Add == // idx = 2 -> :method: GET @@ -424,7 +605,7 @@ private void checkReadFirstRequestWithoutHuffman() { assertEquals(1, hpackReader.dynamicTableHeaderCount); // [ 1] (s = 57) :authority: www.example.com - Header entry = hpackReader.dynamicTable[headerTableLength() - 1]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":authority", "www.example.com", 57); // Table size: 57 @@ -457,11 +638,11 @@ private void checkReadSecondRequestWithoutHuffman() { assertEquals(2, hpackReader.dynamicTableHeaderCount); // [ 1] (s = 53) cache-control: no-cache - Header entry = hpackReader.dynamicTable[headerTableLength() - 2]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 2]; checkEntry(entry, "cache-control", "no-cache", 53); // [ 2] (s = 57) :authority: www.example.com - entry = hpackReader.dynamicTable[headerTableLength() - 1]; + entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":authority", "www.example.com", 57); // Table size: 110 @@ -496,15 +677,15 @@ private void checkReadThirdRequestWithoutHuffman() { assertEquals(3, hpackReader.dynamicTableHeaderCount); // [ 1] (s = 54) custom-key: custom-value - Header entry = hpackReader.dynamicTable[headerTableLength() - 3]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 3]; checkEntry(entry, "custom-key", "custom-value", 54); // [ 2] (s = 53) cache-control: no-cache - entry = hpackReader.dynamicTable[headerTableLength() - 2]; + entry = hpackReader.dynamicTable[readerHeaderTableLength() - 2]; checkEntry(entry, "cache-control", "no-cache", 53); // [ 3] (s = 57) :authority: www.example.com - entry = hpackReader.dynamicTable[headerTableLength() - 1]; + entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":authority", "www.example.com", 57); // Table size: 164 @@ -554,7 +735,7 @@ private void checkReadFirstRequestWithHuffman() { assertEquals(1, hpackReader.dynamicTableHeaderCount); // [ 1] (s = 57) :authority: www.example.com - Header entry = hpackReader.dynamicTable[headerTableLength() - 1]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":authority", "www.example.com", 57); // Table size: 57 @@ -588,11 +769,11 @@ private void checkReadSecondRequestWithHuffman() { assertEquals(2, hpackReader.dynamicTableHeaderCount); // [ 1] (s = 53) cache-control: no-cache - Header entry = hpackReader.dynamicTable[headerTableLength() - 2]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 2]; checkEntry(entry, "cache-control", "no-cache", 53); // [ 2] (s = 57) :authority: www.example.com - entry = hpackReader.dynamicTable[headerTableLength() - 1]; + entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":authority", "www.example.com", 57); // Table size: 110 @@ -629,15 +810,15 @@ private void checkReadThirdRequestWithHuffman() { assertEquals(3, hpackReader.dynamicTableHeaderCount); // [ 1] (s = 54) custom-key: custom-value - Header entry = hpackReader.dynamicTable[headerTableLength() - 3]; + Header entry = hpackReader.dynamicTable[readerHeaderTableLength() - 3]; checkEntry(entry, "custom-key", "custom-value", 54); // [ 2] (s = 53) cache-control: no-cache - entry = hpackReader.dynamicTable[headerTableLength() - 2]; + entry = hpackReader.dynamicTable[readerHeaderTableLength() - 2]; checkEntry(entry, "cache-control", "no-cache", 53); // [ 3] (s = 57) :authority: www.example.com - entry = hpackReader.dynamicTable[headerTableLength() - 1]; + entry = hpackReader.dynamicTable[readerHeaderTableLength() - 1]; checkEntry(entry, ":authority", "www.example.com", 57); // Table size: 164 @@ -702,7 +883,7 @@ private void checkReadThirdRequestWithHuffman() { @Test public void lowercaseHeaderNameBeforeEmit() throws IOException { hpackWriter.writeHeaders(Arrays.asList(new Header("FoO", "BaR"))); - assertBytes(0, 3, 'f', 'o', 'o', 3, 'B', 'a', 'R'); + assertBytes(0x40, 3, 'f', 'o', 'o', 3, 'B', 'a', 'R'); } @Test public void mixedCaseHeaderNameIsMalformed() throws IOException { @@ -720,6 +901,224 @@ private void checkReadThirdRequestWithHuffman() { assertEquals(ByteString.EMPTY, newReader(byteStream(0)).readByteString()); } + @Test + public void emitsDynamicTableSizeUpdate() throws IOException { + hpackWriter.resizeHeaderTable(2048); + hpackWriter.writeHeaders(Arrays.asList(new Header("foo", "bar"))); + assertBytes( + 0x3F, 0xE1, 0xF, // Dynamic table size update (size = 2048). + 0x40, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'); + + hpackWriter.resizeHeaderTable(8192); + hpackWriter.writeHeaders(Arrays.asList(new Header("bar", "foo"))); + assertBytes( + 0x3F, 0xE1, 0x3F, // Dynamic table size update (size = 8192). + 0x40, 3, 'b', 'a', 'r', 3, 'f', 'o', 'o'); + + // No more dynamic table updates should be emitted. + hpackWriter.writeHeaders(Arrays.asList(new Header("far", "boo"))); + assertBytes(0x40, 3, 'f', 'a', 'r', 3, 'b', 'o', 'o'); + } + + @Test + public void noDynamicTableSizeUpdateWhenSizeIsEqual() throws IOException { + int currentSize = hpackWriter.headerTableSizeSetting; + hpackWriter.resizeHeaderTable(currentSize); + hpackWriter.writeHeaders(Arrays.asList(new Header("foo", "bar"))); + + assertBytes(0x40, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'); + } + + @Test + public void growDynamicTableSize() throws IOException { + hpackWriter.resizeHeaderTable(8192); + hpackWriter.resizeHeaderTable(16384); + hpackWriter.writeHeaders(Arrays.asList(new Header("foo", "bar"))); + + assertBytes( + 0x3F, 0xE1, 0x7F, // Dynamic table size update (size = 16384). + 0x40, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'); + } + + @Test + public void shrinkDynamicTableSize() throws IOException { + hpackWriter.resizeHeaderTable(2048); + hpackWriter.resizeHeaderTable(0); + hpackWriter.writeHeaders(Arrays.asList(new Header("foo", "bar"))); + + assertBytes( + 0x20, // Dynamic size update (size = 0). + 0x40, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'); + } + + @Test + public void manyDynamicTableSizeChanges() throws IOException { + hpackWriter.resizeHeaderTable(16384); + hpackWriter.resizeHeaderTable(8096); + hpackWriter.resizeHeaderTable(0); + hpackWriter.resizeHeaderTable(4096); + hpackWriter.resizeHeaderTable(2048); + hpackWriter.writeHeaders(Arrays.asList(new Header("foo", "bar"))); + + assertBytes( + 0x20, // Dynamic size update (size = 0). + 0x3F, 0xE1, 0xF, // Dynamic size update (size = 2048). + 0x40, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'); + } + + @Test + public void dynamicTableEvictionWhenSizeLowered() throws IOException { + List
    headerBlock = + headerEntries( + "custom-key1", "custom-header", + "custom-key2", "custom-header"); + hpackWriter.writeHeaders(headerBlock); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.resizeHeaderTable(56); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.resizeHeaderTable(0); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void noEvictionOnDynamicTableSizeIncrease() throws IOException { + List
    headerBlock = + headerEntries( + "custom-key1", "custom-header", + "custom-key2", "custom-header"); + hpackWriter.writeHeaders(headerBlock); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.resizeHeaderTable(8192); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void dynamicTableSizeHasAnUpperBound() { + hpackWriter.resizeHeaderTable(1048576); + assertEquals(16384, hpackWriter.maxDynamicTableByteCount()); + } + + @Test + public void huffmanEncode() throws IOException { + hpackWriter = new Hpack.Writer(4096, true, bytesOut); + hpackWriter.writeHeaders(headerEntries("foo", "bar")); + + ByteString expected = new Buffer() + .writeByte(0x40) // Literal header, new name. + .writeByte(0x82) // String literal is Huffman encoded (len = 2). + .writeByte(0x94) // 'foo' Huffman encoded. + .writeByte(0xE7) + .writeByte(3) // String literal not Huffman encoded (len = 3). + .writeByte('b') + .writeByte('a') + .writeByte('r') + .readByteString(); + + ByteString actual = bytesOut.readByteString(); + assertEquals(expected, actual); + } + + @Test + public void staticTableIndexedHeaders() throws IOException { + hpackWriter.writeHeaders(headerEntries(":method", "GET")); + assertBytes(0x82); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":method", "POST")); + assertBytes(0x83); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":path", "/")); + assertBytes(0x84); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":path", "/index.html")); + assertBytes(0x85); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":scheme", "http")); + assertBytes(0x86); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":scheme", "https")); + assertBytes(0x87); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void dynamicTableIndexedHeader() throws IOException { + hpackWriter.writeHeaders(headerEntries("custom-key", "custom-header")); + assertBytes(0x40, + 10, 'c', 'u', 's', 't', 'o', 'm', '-', 'k', 'e', 'y', + 13, 'c', 'u', 's', 't', 'o', 'm', '-', 'h', 'e', 'a', 'd', 'e', 'r'); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries("custom-key", "custom-header")); + assertBytes(0xbe); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void doNotIndexPseudoHeaders() throws IOException { + hpackWriter.writeHeaders(headerEntries(":method", "PUT")); + assertBytes(0x02, 3, 'P', 'U', 'T'); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":path", "/okhttp")); + assertBytes(0x04, 7, '/', 'o', 'k', 'h', 't', 't', 'p'); + assertEquals(0, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void incrementalIndexingWithAuthorityPseudoHeader() throws IOException { + hpackWriter.writeHeaders(headerEntries(":authority", "foo.com")); + assertBytes(0x41, 7, 'f', 'o', 'o', '.', 'c', 'o', 'm'); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":authority", "foo.com")); + assertBytes(0xbe); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + // If the :authority header somehow changes, it should be re-added to the dynamic table. + hpackWriter.writeHeaders(headerEntries(":authority", "bar.com")); + assertBytes(0x41, 7, 'b', 'a', 'r', '.', 'c', 'o', 'm'); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries(":authority", "bar.com")); + assertBytes(0xbe); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void incrementalIndexingWithStaticTableIndexedName() throws IOException { + hpackWriter.writeHeaders(headerEntries("accept-encoding", "gzip")); + assertBytes(0x50, 4, 'g', 'z', 'i', 'p'); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries("accept-encoding", "gzip")); + assertBytes(0xbe); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + } + + @Test + public void incrementalIndexingWithDynamcTableIndexedName() throws IOException { + hpackWriter.writeHeaders(headerEntries("foo", "bar")); + assertBytes(0x40, 3, 'f', 'o', 'o', 3, 'b', 'a', 'r'); + assertEquals(1, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries("foo", "bar1")); + assertBytes(0x7e, 4, 'b', 'a', 'r', '1'); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + + hpackWriter.writeHeaders(headerEntries("foo", "bar1")); + assertBytes(0xbe); + assertEquals(2, hpackWriter.dynamicTableHeaderCount); + } + + private Hpack.Reader newReader(Buffer source) { return new Hpack.Reader(4096, source); } @@ -748,7 +1147,7 @@ private ByteString intArrayToByteArray(int[] bytes) { return ByteString.of(data); } - private int headerTableLength() { + private int readerHeaderTableLength() { return hpackReader.dynamicTable.length; } } From 079219bbc9c46f3bd99e7cce94429efb2079ff09 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Wed, 9 Oct 2019 10:47:34 -0400 Subject: [PATCH 080/131] Update to GSON 2.8.5 and protobuf 3.10.0 --- COMPILING.md | 12 ++++++------ README.md | 6 +++--- android-interop-testing/app/build.gradle | 2 +- build.gradle | 4 ++-- buildscripts/build_docker.sh | 4 ++-- buildscripts/make_dependencies.bat | 2 +- buildscripts/make_dependencies.sh | 2 +- examples/android/helloworld/app/build.gradle | 2 +- examples/android/routeguide/app/build.gradle | 2 +- examples/android/strictmode/app/build.gradle | 2 +- examples/build.gradle | 2 +- examples/example-alts/build.gradle | 2 +- examples/example-gauth/build.gradle | 2 +- examples/example-gauth/pom.xml | 2 +- .../android/helloworld/app/build.gradle | 2 +- examples/example-kotlin/build.gradle | 2 +- examples/example-tls/build.gradle | 2 +- examples/example-tls/pom.xml | 2 +- examples/pom.xml | 4 ++-- repositories.bzl | 10 +++++----- 20 files changed, 34 insertions(+), 34 deletions(-) diff --git a/COMPILING.md b/COMPILING.md index fdd3a9a7868..ebb5fe31872 100644 --- a/COMPILING.md +++ b/COMPILING.md @@ -23,7 +23,7 @@ $ ./gradlew publishToMavenLocal ``` ### Notes for IntelliJ -Building in IntelliJ works best when you import the project as a Gradle project and delegate IDE +Building in IntelliJ works best when you import the project as a Gradle project and delegate IDE build/run actions to Gradle. You can find this setting at: @@ -42,7 +42,7 @@ The codegen plugin is C++ code and requires protobuf 3.0.0 or later. For Linux, Mac and MinGW: ``` -$ PROTOBUF_VERSION=3.9.0 +$ PROTOBUF_VERSION=3.10.0 $ curl -LO https://github.com/protocolbuffers/protobuf/releases/download/v$PROTOBUF_VERSION/protobuf-all-$PROTOBUF_VERSION.tar.gz $ tar xzf protobuf-all-$PROTOBUF_VERSION.tar.gz $ cd protobuf-$PROTOBUF_VERSION @@ -75,16 +75,16 @@ When building on Windows and VC++, you need to specify project properties for Gradle to find protobuf: ``` .\gradlew publishToMavenLocal ^ - -PvcProtobufInclude=C:\path\to\protobuf-3.9.0\src ^ - -PvcProtobufLibs=C:\path\to\protobuf-3.9.0\vsprojects\Release ^ + -PvcProtobufInclude=C:\path\to\protobuf-3.10.0\src ^ + -PvcProtobufLibs=C:\path\to\protobuf-3.10.0\vsprojects\Release ^ -PtargetArch=x86_32 ``` Since specifying those properties every build is bothersome, you can instead create ``\gradle.properties`` with contents like: ``` -vcProtobufInclude=C:\\path\\to\\protobuf-3.9.0\\src -vcProtobufLibs=C:\\path\\to\\protobuf-3.9.0\\vsprojects\\Release +vcProtobufInclude=C:\\path\\to\\protobuf-3.10.0\\src +vcProtobufLibs=C:\\path\\to\\protobuf-3.10.0\\vsprojects\\Release targetArch=x86_32 ``` diff --git a/README.md b/README.md index 2b2e5e30384..b2a7fc5c8bb 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,7 @@ For protobuf-based codegen integrated with the Maven build system, you can use protobuf-maven-plugin 0.6.1 - com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier} + com.google.protobuf:protoc:3.10.0:exe:${os.detected.classifier} grpc-java io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier} @@ -130,7 +130,7 @@ plugins { protobuf { protoc { - artifact = "com.google.protobuf:protoc:3.9.0" + artifact = "com.google.protobuf:protoc:3.10.0" } plugins { grpc { @@ -165,7 +165,7 @@ We recommend using the [grpc-java-api-checker](https://github.com/grpc/grpc-java-api-checker) (an [Error Prone](https://github.com/google/error-prone) plugin) to check for usages of `@ExperimentalApi` and `@Internal` in any library code -that depends on gRPC. It may also be used to check for `@Internal` usage or +that depends on gRPC. It may also be used to check for `@Internal` usage or unintended `@ExperimentalApi` consumption in non-library code. How to Build diff --git a/android-interop-testing/app/build.gradle b/android-interop-testing/app/build.gradle index b8ea5302e86..ea4e83ec760 100644 --- a/android-interop-testing/app/build.gradle +++ b/android-interop-testing/app/build.gradle @@ -39,7 +39,7 @@ android { } protobuf { - protoc { artifact = 'com.google.protobuf:protoc:3.9.0' } + protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION diff --git a/build.gradle b/build.gradle index 6d8ff89425e..146487635b9 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ subprojects { nettyVersion = '4.1.42.Final' guavaVersion = '28.1-android' googleauthVersion = '0.17.1' - protobufVersion = '3.9.0' + protobufVersion = '3.10.0' protocVersion = protobufVersion opencensusVersion = '0.21.0' @@ -119,7 +119,7 @@ subprojects { android_annotations: "com.google.android:annotations:4.1.1.4", animalsniffer_annotations: "org.codehaus.mojo:animal-sniffer-annotations:1.17", errorprone: "com.google.errorprone:error_prone_annotations:2.3.2", - gson: "com.google.code.gson:gson:2.7", + gson: "com.google.code.gson:gson:2.8.5", guava: "com.google.guava:guava:${guavaVersion}", hpack: 'com.twitter:hpack:0.10.1', javax_annotation: 'javax.annotation:javax.annotation-api:1.2', diff --git a/buildscripts/build_docker.sh b/buildscripts/build_docker.sh index 105f412660e..5a8a405464b 100755 --- a/buildscripts/build_docker.sh +++ b/buildscripts/build_docker.sh @@ -2,7 +2,7 @@ set -eu -o pipefail readonly proto_dir="$(mktemp -d --tmpdir protobuf.XXXXXX)" -wget -O - https://github.com/google/protobuf/archive/v3.9.0.tar.gz | tar xz -C "$proto_dir" +wget -O - https://github.com/google/protobuf/archive/v3.10.0.tar.gz | tar xz -C "$proto_dir" -docker build -t protoc-artifacts "$proto_dir"/protobuf-3.9.0/protoc-artifacts +docker build -t protoc-artifacts "$proto_dir"/protobuf-3.10.0/protoc-artifacts rm -r "$proto_dir" diff --git a/buildscripts/make_dependencies.bat b/buildscripts/make_dependencies.bat index 32783be493d..8a4ea2e4ca4 100644 --- a/buildscripts/make_dependencies.bat +++ b/buildscripts/make_dependencies.bat @@ -1,4 +1,4 @@ -set PROTOBUF_VER=3.9.0 +set PROTOBUF_VER=3.10.0 set CMAKE_NAME=cmake-3.3.2-win32-x86 if not exist "protobuf-%PROTOBUF_VER%\cmake\build\Release\" ( diff --git a/buildscripts/make_dependencies.sh b/buildscripts/make_dependencies.sh index 2e2bb8ff832..c7b84793786 100755 --- a/buildscripts/make_dependencies.sh +++ b/buildscripts/make_dependencies.sh @@ -3,7 +3,7 @@ # Build protoc set -evux -o pipefail -PROTOBUF_VERSION=3.9.0 +PROTOBUF_VERSION=3.10.0 # ARCH is 64 bit unless otherwise specified. ARCH="${ARCH:-64}" diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle index 2146f8a8bb3..05380eaa3ac 100644 --- a/examples/android/helloworld/app/build.gradle +++ b/examples/android/helloworld/app/build.gradle @@ -27,7 +27,7 @@ android { } protobuf { - protoc { artifact = 'com.google.protobuf:protoc:3.9.0' } + protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION diff --git a/examples/android/routeguide/app/build.gradle b/examples/android/routeguide/app/build.gradle index 449b8d01109..26c44dcddd8 100644 --- a/examples/android/routeguide/app/build.gradle +++ b/examples/android/routeguide/app/build.gradle @@ -26,7 +26,7 @@ android { } protobuf { - protoc { artifact = 'com.google.protobuf:protoc:3.9.0' } + protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION diff --git a/examples/android/strictmode/app/build.gradle b/examples/android/strictmode/app/build.gradle index a9ed91be8bd..06a3091c35b 100644 --- a/examples/android/strictmode/app/build.gradle +++ b/examples/android/strictmode/app/build.gradle @@ -27,7 +27,7 @@ android { } protobuf { - protoc { artifact = 'com.google.protobuf:protoc:3.9.0' } + protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION diff --git a/examples/build.gradle b/examples/build.gradle index 76113892d4b..553e4f680a7 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION -def protobufVersion = '3.9.0' +def protobufVersion = '3.10.0' def protocVersion = protobufVersion dependencies { diff --git a/examples/example-alts/build.gradle b/examples/example-alts/build.gradle index c321d7bb3ca..fcc6a13bc75 100644 --- a/examples/example-alts/build.gradle +++ b/examples/example-alts/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION -def protocVersion = '3.9.0' +def protocVersion = '3.10.0' dependencies { // grpc-alts transitively depends on grpc-netty-shaded, grpc-protobuf, and grpc-stub diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index c10fa437596..3cdc6c0a9ea 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -24,7 +24,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION -def protobufVersion = '3.9.0' +def protobufVersion = '3.10.0' def protocVersion = protobufVersion diff --git a/examples/example-gauth/pom.xml b/examples/example-gauth/pom.xml index 019657f8747..232822d0122 100644 --- a/examples/example-gauth/pom.xml +++ b/examples/example-gauth/pom.xml @@ -13,7 +13,7 @@ UTF-8 1.25.0-SNAPSHOT - 3.9.0 + 3.10.0 1.7 1.7 diff --git a/examples/example-kotlin/android/helloworld/app/build.gradle b/examples/example-kotlin/android/helloworld/app/build.gradle index 0868c24fe99..94af988101e 100644 --- a/examples/example-kotlin/android/helloworld/app/build.gradle +++ b/examples/example-kotlin/android/helloworld/app/build.gradle @@ -49,7 +49,7 @@ android { } protobuf { - protoc { artifact = 'com.google.protobuf:protoc:3.9.0' } + protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION diff --git a/examples/example-kotlin/build.gradle b/examples/example-kotlin/build.gradle index 4530055b0fa..7410037ab60 100644 --- a/examples/example-kotlin/build.gradle +++ b/examples/example-kotlin/build.gradle @@ -41,7 +41,7 @@ dependencies { } protobuf { - protoc { artifact = 'com.google.protobuf:protoc:3.9.0' } + protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { grpc { artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" } } diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index ac24a272c1b..37479d41cf5 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -25,7 +25,7 @@ targetCompatibility = 1.7 // updating the version in our release process. def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION def nettyTcNativeVersion = '2.0.26.Final' -def protocVersion = '3.9.0' +def protocVersion = '3.10.0' dependencies { implementation "io.grpc:grpc-netty:${grpcVersion}" diff --git a/examples/example-tls/pom.xml b/examples/example-tls/pom.xml index 998b140e1a1..6391c8719c3 100644 --- a/examples/example-tls/pom.xml +++ b/examples/example-tls/pom.xml @@ -13,7 +13,7 @@ UTF-8 1.25.0-SNAPSHOT - 3.9.0 + 3.10.0 2.0.25.Final 1.7 diff --git a/examples/pom.xml b/examples/pom.xml index 274baa2d3f7..feb3748d817 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -13,8 +13,8 @@ UTF-8 1.25.0-SNAPSHOT - 3.9.0 - 3.9.0 + 3.10.0 + 3.10.0 1.7 1.7 diff --git a/repositories.bzl b/repositories.bzl index 842d5647302..69f5c60149a 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -223,9 +223,9 @@ def com_google_code_findbugs_jsr305(): def com_google_code_gson(): jvm_maven_import_external( name = "com_google_code_gson_gson", - artifact = "com.google.code.gson:gson:jar:2.7", + artifact = "com.google.code.gson:gson:jar:2.8.5", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "2d43eb5ea9e133d2ee2405cc14f5ee08951b8361302fdd93494a3a997b508d32", + artifact_sha256 = "233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81", licenses = ["notice"], # Apache 2.0 ) @@ -272,9 +272,9 @@ def com_google_protobuf(): # This statement defines the @com_google_protobuf repo. http_archive( name = "com_google_protobuf", - sha256 = "8eb5ca331ab8ca0da2baea7fc0607d86c46c80845deca57109a5d637ccb93bb4", - strip_prefix = "protobuf-3.9.0", - urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.9.0.zip"], + sha256 = "33cba8b89be6c81b1461f1c438424f7a1aa4e31998dbe9ed6f8319583daac8c7", + strip_prefix = "protobuf-3.10.0", + urls = ["https://github.com/protocolbuffers/protobuf/archive/v3.10.0.zip"], ) def com_google_protobuf_javalite(): From 7e8e9d6a86631284287000c38bed87907aa06583 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 9 Oct 2019 07:51:18 -0700 Subject: [PATCH 081/131] bazel: Remove deps that protobuf includes net_zlib is no longer used ("zlib" is used instead). Zlib and skylib are both included via protobuf_deps(). With the language-specific rules needing to be imported (e.g., rules_proto, rules_java) we are relying on protobuf_deps() pretty heavily starting in Protobuf 3.10, so we aren't losing much to remove these two deps. --- repositories.bzl | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/repositories.bzl b/repositories.bzl index 69f5c60149a..68ad31071dd 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -38,7 +38,6 @@ IO_GRPC_GRPC_JAVA_OVERRIDE_TARGETS = { } def grpc_java_repositories( - omit_bazel_skylib = False, omit_com_google_android_annotations = False, omit_com_google_api_grpc_google_common_protos = False, omit_com_google_auth_google_auth_library_credentials = False, @@ -73,12 +72,9 @@ def grpc_java_repositories( omit_io_perfmark = False, omit_javax_annotation = False, omit_junit_junit = False, - omit_net_zlib = False, omit_org_apache_commons_lang3 = False, omit_org_codehaus_mojo_animal_sniffer_annotations = False): """Imports dependencies for grpc-java.""" - if not omit_bazel_skylib: - bazel_skylib() if not omit_com_google_android_annotations: com_google_android_annotations() if not omit_com_google_api_grpc_google_common_protos: @@ -147,8 +143,6 @@ def grpc_java_repositories( javax_annotation() if not omit_junit_junit: junit_junit() - if not omit_net_zlib: - net_zlib() if not omit_org_apache_commons_lang3: org_apache_commons_lang3() if not omit_org_codehaus_mojo_animal_sniffer_annotations: @@ -167,14 +161,6 @@ def grpc_java_repositories( actual = "@com_google_errorprone_error_prone_annotations//jar", ) -def bazel_skylib(): - http_archive( - name = "bazel_skylib", - sha256 = "bce240a0749dfc52fab20dce400b4d5cf7c28b239d64f8fd1762b3c9470121d8", - strip_prefix = "bazel-skylib-0.7.0", - urls = ["https://github.com/bazelbuild/bazel-skylib/archive/0.7.0.zip"], - ) - def com_google_android_annotations(): jvm_maven_import_external( name = "com_google_android_annotations", @@ -475,15 +461,6 @@ def junit_junit(): licenses = ["notice"], # EPL 1.0 ) -def net_zlib(): - http_archive( - name = "net_zlib", - build_file = "@com_google_protobuf//:third_party/zlib.BUILD", - sha256 = "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1", - strip_prefix = "zlib-1.2.11", - urls = ["https://zlib.net/zlib-1.2.11.tar.gz"], - ) - def org_apache_commons_lang3(): jvm_maven_import_external( name = "org_apache_commons_commons_lang3", From 024a46bd11120e706f2ee8fb10d1cbefc9be9b5a Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 9 Oct 2019 14:46:17 -0700 Subject: [PATCH 082/131] bazel: Support --incompatible_load_proto_rules_from_bzl This flag will be enabled by default in Bazel 1.0 Since I changed the grpc-proto repo version for Bazel, I also synced the protos. --- alts/BUILD.bazel | 1 + examples/BUILD.bazel | 3 ++- examples/example-alts/BUILD.bazel | 1 + examples/example-tls/BUILD.bazel | 1 + grpclb/BUILD.bazel | 1 + repositories.bzl | 6 +++--- services/src/main/proto/grpc/channelz/v1/channelz.proto | 2 +- 7 files changed, 10 insertions(+), 5 deletions(-) diff --git a/alts/BUILD.bazel b/alts/BUILD.bazel index 6512c56f222..ff973dba514 100644 --- a/alts/BUILD.bazel +++ b/alts/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("//:java_grpc_library.bzl", "java_grpc_library") java_library( diff --git a/examples/BUILD.bazel b/examples/BUILD.bazel index 7586cfb3f07..db8916d700b 100644 --- a/examples/BUILD.bazel +++ b/examples/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") proto_library( @@ -71,7 +72,7 @@ java_library( ":route_guide_java_proto", "@com_google_api_grpc_proto_google_common_protos//jar", "@com_google_code_findbugs_jsr305//jar", - "@com_google_code_gson_gson//:com_google_code_gson_gson", + "@com_google_code_gson_gson", "@com_google_guava_guava//jar", "@com_google_protobuf//:protobuf_java", "@com_google_protobuf//:protobuf_java_util", diff --git a/examples/example-alts/BUILD.bazel b/examples/example-alts/BUILD.bazel index a9afbe7fde5..0404dcccf81 100644 --- a/examples/example-alts/BUILD.bazel +++ b/examples/example-alts/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") proto_library( diff --git a/examples/example-tls/BUILD.bazel b/examples/example-tls/BUILD.bazel index d615b5c4aa1..f75250c235d 100644 --- a/examples/example-tls/BUILD.bazel +++ b/examples/example-tls/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("@io_grpc_grpc_java//:java_grpc_library.bzl", "java_grpc_library") proto_library( diff --git a/grpclb/BUILD.bazel b/grpclb/BUILD.bazel index d48073fc5cb..b261225ac1d 100644 --- a/grpclb/BUILD.bazel +++ b/grpclb/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_proto//proto:defs.bzl", "proto_library") load("//:java_grpc_library.bzl", "java_grpc_library") java_library( diff --git a/repositories.bzl b/repositories.bzl index 68ad31071dd..57d71f11296 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -302,9 +302,9 @@ def com_squareup_okio(): def io_grpc_grpc_proto(): http_archive( name = "io_grpc_grpc_proto", - sha256 = "873f3fdec7ed052f899aef83fc897926729713d96d7ccdb2df22843dc702ef3a", - strip_prefix = "grpc-proto-96ecba6941c67b1da2af598330c60cf9b0336051", - urls = ["https://github.com/grpc/grpc-proto/archive/96ecba6941c67b1da2af598330c60cf9b0336051.zip"], + sha256 = "9d96f861f01ed9e3d805024e72a6b218b626da2114c69c1cad5d0e967c8e23be", + strip_prefix = "grpc-proto-435d723289d348e1bc420d420b364369d565182a", + urls = ["https://github.com/grpc/grpc-proto/archive/435d723289d348e1bc420d420b364369d565182a.zip"], ) def io_netty_buffer(): diff --git a/services/src/main/proto/grpc/channelz/v1/channelz.proto b/services/src/main/proto/grpc/channelz/v1/channelz.proto index 20de23f7fa3..f0b3b10837e 100644 --- a/services/src/main/proto/grpc/channelz/v1/channelz.proto +++ b/services/src/main/proto/grpc/channelz/v1/channelz.proto @@ -165,7 +165,7 @@ message ChannelRef { reserved 3, 4, 5, 6, 7, 8; } -// ChannelRef is a reference to a Subchannel. +// SubchannelRef is a reference to a Subchannel. message SubchannelRef { // The globally unique id for this subchannel. Must be a positive number. int64 subchannel_id = 7; From a633b53f9545723d68e3736d1e913fc854aeb815 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Wed, 9 Oct 2019 14:52:09 -0700 Subject: [PATCH 083/131] xds: SdsX509TrustManager implementation for XDS and SDS (#6254) --- .../grpc/xds/sds/trust/CertificateUtils.java | 53 ++++ .../xds/sds/trust/SdsX509TrustManager.java | 280 ++++++++++++++++++ xds/src/test/certs/client.pem | 18 ++ xds/src/test/certs/server1.pem | 16 + .../sds/trust/SdsX509TrustManagerTest.java | 236 +++++++++++++++ 5 files changed, 603 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java create mode 100644 xds/src/test/certs/client.pem create mode 100644 xds/src/test/certs/server1.pem create mode 100644 xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java b/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java new file mode 100644 index 00000000000..481abd8e635 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java @@ -0,0 +1,53 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds.trust; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; + +/** + * Contains certificate utility method(s). + */ +final class CertificateUtils { + + private static CertificateFactory factory; + + private static synchronized void initInstance() throws CertificateException { + if (factory == null) { + factory = CertificateFactory.getInstance("X.509"); + } + } + + static synchronized X509Certificate[] toX509Certificates(String fileName) + throws CertificateException, IOException { + initInstance(); + FileInputStream fis = new FileInputStream(fileName); + BufferedInputStream bis = new BufferedInputStream(fis); + try { + Collection certs = factory.generateCertificates(bis); + return certs.toArray(new X509Certificate[0]); + } finally { + bis.close(); + } + } +} diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java b/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java new file mode 100644 index 00000000000..a1ae0d70db3 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java @@ -0,0 +1,280 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds.trust; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import java.net.Socket; +import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import javax.annotation.Nullable; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.X509ExtendedTrustManager; +import javax.net.ssl.X509TrustManager; + +/** + * Extension of {@link X509ExtendedTrustManager} that implements verification of + * SANs (subject-alternate-names) against the list in CertificateValidationContext. + */ +final class SdsX509TrustManager extends X509ExtendedTrustManager implements X509TrustManager { + + // ref: io.grpc.okhttp.internal.OkHostnameVerifier and + // sun.security.x509.GeneralNameInterface + private static final int ALT_DNS_NAME = 2; + private static final int ALT_URI_NAME = 6; + private static final int ALT_IPA_NAME = 7; + + private final X509ExtendedTrustManager delegate; + private final CertificateValidationContext certContext; + + SdsX509TrustManager(@Nullable CertificateValidationContext certContext, + X509ExtendedTrustManager delegate) { + checkNotNull(delegate, "delegate"); + this.certContext = certContext; + this.delegate = delegate; + } + + // Copied from OkHostnameVerifier.verifyHostName(). + private static boolean verifyDnsNameInPattern(String pattern, String sanToVerify) { + // Basic sanity checks + // Check length == 0 instead of .isEmpty() to support Java 5. + if (sanToVerify == null + || sanToVerify.length() == 0 + || sanToVerify.startsWith(".") + || sanToVerify.endsWith("..")) { + // Invalid domain name + return false; + } + if (pattern == null + || pattern.length() == 0 + || pattern.startsWith(".") + || pattern.endsWith("..")) { + // Invalid pattern/domain name + return false; + } + + // Normalize sanToVerify and pattern by turning them into absolute domain names if they are not + // yet absolute. This is needed because server certificates do not normally contain absolute + // names or patterns, but they should be treated as absolute. At the same time, any sanToVerify + // presented to this method should also be treated as absolute for the purposes of matching + // to the server certificate. + // www.android.com matches www.android.com + // www.android.com matches www.android.com. + // www.android.com. matches www.android.com. + // www.android.com. matches www.android.com + if (!sanToVerify.endsWith(".")) { + sanToVerify += '.'; + } + if (!pattern.endsWith(".")) { + pattern += '.'; + } + // sanToVerify and pattern are now absolute domain names. + + pattern = pattern.toLowerCase(Locale.US); + // sanToVerify and pattern are now in lower case -- domain names are case-insensitive. + + if (!pattern.contains("*")) { + // Not a wildcard pattern -- sanToVerify and pattern must match exactly. + return sanToVerify.equals(pattern); + } + // Wildcard pattern + + // WILDCARD PATTERN RULES: + // 1. Asterisk (*) is only permitted in the left-most domain name label and must be the + // only character in that label (i.e., must match the whole left-most label). + // For example, *.example.com is permitted, while *a.example.com, a*.example.com, + // a*b.example.com, a.*.example.com are not permitted. + // 2. Asterisk (*) cannot match across domain name labels. + // For example, *.example.com matches test.example.com but does not match + // sub.test.example.com. + // 3. Wildcard patterns for single-label domain names are not permitted. + + if (!pattern.startsWith("*.") || pattern.indexOf('*', 1) != -1) { + // Asterisk (*) is only permitted in the left-most domain name label and must be the only + // character in that label + return false; + } + + // Optimization: check whether sanToVerify is too short to match the pattern. sanToVerify must + // be at + // least as long as the pattern because asterisk must match the whole left-most label and + // sanToVerify starts with a non-empty label. Thus, asterisk has to match one or more + // characters. + if (sanToVerify.length() < pattern.length()) { + // sanToVerify too short to match the pattern. + return false; + } + + if ("*.".equals(pattern)) { + // Wildcard pattern for single-label domain name -- not permitted. + return false; + } + + // sanToVerify must end with the region of pattern following the asterisk. + String suffix = pattern.substring(1); + if (!sanToVerify.endsWith(suffix)) { + // sanToVerify does not end with the suffix + return false; + } + + // Check that asterisk did not match across domain name labels. + int suffixStartIndexInHostName = sanToVerify.length() - suffix.length(); + // Asterisk is matching across domain name labels -- not permitted. + return suffixStartIndexInHostName <= 0 + || sanToVerify.lastIndexOf('.', suffixStartIndexInHostName - 1) == -1; + + // sanToVerify matches pattern + } + + private static boolean verifyDnsNameInSanList(String altNameFromCert, + List verifySanList) { + for (String verifySan : verifySanList) { + if (verifyDnsNameInPattern(altNameFromCert, verifySan)) { + return true; + } + } + return false; + } + + /** + * helper function for verifying URI or IP address. For now we compare IP addresses as strings + * without any regard to IPv4 vs IPv6. + * + * @param stringFromCert either URI or IP address + * @param verifySanList list of SANs from certificate context + * @return true if there is a match + */ + private static boolean verifyStringInSanList(String stringFromCert, List verifySanList) { + for (String sanToVerify : verifySanList) { + if (sanToVerify.equalsIgnoreCase(stringFromCert)) { + return true; + } + } + return false; + } + + private static boolean verifyOneSanInList(List entry, List verifySanList) + throws CertificateParsingException { + // from OkHostnameVerifier.getSubjectAltNames + if (entry == null || entry.size() < 2) { + throw new CertificateParsingException("Invalid SAN entry"); + } + Integer altNameType = (Integer) entry.get(0); + if (altNameType == null) { + throw new CertificateParsingException("Invalid SAN entry: null altNameType"); + } + String altNameFromCert = (String) entry.get(1); + switch (altNameType) { + case ALT_DNS_NAME: + return verifyDnsNameInSanList(altNameFromCert, verifySanList); + case ALT_URI_NAME: + case ALT_IPA_NAME: + return verifyStringInSanList(altNameFromCert, verifySanList); + default: + throw new CertificateParsingException("Unsupported altNameType: " + altNameType); + } + } + + // logic from Envoy::Extensions::TransportSockets::Tls::ContextImpl::verifySubjectAltName + private static void verifySubjectAltNameInLeaf(X509Certificate cert, List verifyList) + throws CertificateException { + Collection> names = cert.getSubjectAlternativeNames(); + if (names == null || names.size() == 0) { + throw new CertificateException("Peer certificate SAN check failed"); + } + for (List name : names) { + if (verifyOneSanInList(name, verifyList)) { + return; + } + } + // at this point there's no match + throw new CertificateException("Peer certificate SAN check failed"); + } + + /** + * Verifies SANs in the peer cert chain against verify_subject_alt_name in the certContext. + * This is called from various check*Trusted methods. + */ + @VisibleForTesting + void verifySubjectAltNameInChain(X509Certificate[] peerCertChain) throws CertificateException { + if (certContext == null) { + return; + } + List verifyList = certContext.getVerifySubjectAltNameList(); + if (verifyList == null || verifyList.isEmpty()) { + return; + } + if (peerCertChain == null || peerCertChain.length < 1) { + throw new CertificateException("Peer certificate(s) missing"); + } + // verify SANs only in the top cert (leaf cert) + verifySubjectAltNameInLeaf(peerCertChain[0], verifyList); + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) + throws CertificateException { + delegate.checkClientTrusted(chain, authType, socket); + verifySubjectAltNameInChain(chain); + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) + throws CertificateException { + delegate.checkClientTrusted(chain, authType, sslEngine); + verifySubjectAltNameInChain(chain); + } + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + delegate.checkClientTrusted(chain, authType); + verifySubjectAltNameInChain(chain); + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) + throws CertificateException { + delegate.checkServerTrusted(chain, authType, socket); + verifySubjectAltNameInChain(chain); + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine sslEngine) + throws CertificateException { + delegate.checkServerTrusted(chain, authType, sslEngine); + verifySubjectAltNameInChain(chain); + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + delegate.checkServerTrusted(chain, authType); + verifySubjectAltNameInChain(chain); + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + return delegate.getAcceptedIssuers(); + } +} diff --git a/xds/src/test/certs/client.pem b/xds/src/test/certs/client.pem new file mode 100644 index 00000000000..913649b97fb --- /dev/null +++ b/xds/src/test/certs/client.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC6TCCAlKgAwIBAgIBCjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTEwMDEwOTU4WhcNMjUxMTA3 +MDEwOTU4WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G +A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYDVQQDDAp0ZXN0Y2xp +ZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsVEfbob4W3lVCDLOVmx9K +cdJnoZdvurGaTY87xNiopmaR8zCR7pFR9BX5L4bNG/PkuVLfVTVAKndyDCQggBBr +UTaEITNbfWK9swHJEr20WnKfhS/wo/Xg5sqNNCrFRmnnnwOA4eDlvmYZEzSnJXV6 +pEro9bBH9uOCWWLqmaev7QIDAQABo4HCMIG/MAkGA1UdEwQCMAAwCwYDVR0PBAQD +AgXgMB0GA1UdDgQWBBQAdbW5Vml/CnYwqdP3mOHDARU+8zBwBgNVHSMEaTBnoVqk +WDBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMY +SW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2GCCQCRxhke +HRoqBzAJBgNVHREEAjAAMAkGA1UdEgQCMAAwDQYJKoZIhvcNAQELBQADgYEAf4MM +k+sdzd720DfrQ0PF2gDauR3M9uBubozDuMuF6ufAuQBJSKGQEGibXbUelrwHmnql +UjTyfolVcxEBVaF4VFHmn7u6vP7S1NexIDdNUHcULqxIb7Tzl8JYq8OOHD2rQy4H +s8BXaVIzw4YcaCGAMS0iDX052Sy7e2JhP8Noxvo= +-----END CERTIFICATE----- diff --git a/xds/src/test/certs/server1.pem b/xds/src/test/certs/server1.pem new file mode 100644 index 00000000000..f3d43fcc5be --- /dev/null +++ b/xds/src/test/certs/server1.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 +-----END CERTIFICATE----- diff --git a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java new file mode 100644 index 00000000000..d118c7eb2d1 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java @@ -0,0 +1,236 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds.trust; + +import static com.google.common.truth.Truth.assertThat; + +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.X509ExtendedTrustManager; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** + * Unit tests for {@link SdsX509TrustManager}. + */ +@RunWith(JUnit4.class) +public class SdsX509TrustManagerTest { + /** + * server1 has 4 SANs. + */ + private static final String SERVER_1_PEM_FILE = "src/test/certs/server1.pem"; + + /** + * client has no SANs. + */ + private static final String CLIENT_PEM_FILE = "src/test/certs/client.pem"; + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private X509ExtendedTrustManager mockDelegate; + + @Test + public void nullCertContextTest() throws CertificateException, IOException { + SdsX509TrustManager trustManager = new SdsX509TrustManager(null, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void emptySanListContextTest() throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void missingPeerCerts() throws CertificateException, FileNotFoundException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("foo.com") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + try { + trustManager.verifySubjectAltNameInChain(null); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected).hasMessageThat() + .isEqualTo("Peer certificate(s) missing"); + } + } + + @Test + public void emptyArrayPeerCerts() throws CertificateException, FileNotFoundException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("foo.com") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + try { + trustManager.verifySubjectAltNameInChain(new X509Certificate[0]); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected).hasMessageThat() + .isEqualTo("Peer certificate(s) missing"); + } + } + + @Test + public void noSansInPeerCerts() throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("foo.com") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(CLIENT_PEM_FILE); + try { + trustManager.verifySubjectAltNameInChain(certs); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected).hasMessageThat() + .isEqualTo("Peer certificate SAN check failed"); + } + } + + @Test + public void oneSanInPeerCertsVerifies() throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("waterzooi.test.google.be") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void oneSanInPeerCertsVerifiesMultipleVerifySans() + throws CertificateException, IOException { + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() + .addVerifySubjectAltName("x.foo.com") + .addVerifySubjectAltName("waterzooi.test.google.be") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void oneSanInPeerCertsNotFoundException() + throws CertificateException, IOException { + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder().addVerifySubjectAltName("x.foo.com").build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + try { + trustManager.verifySubjectAltNameInChain(certs); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed"); + } + } + + @Test + public void wildcardSanInPeerCertsVerifiesMultipleVerifySans() + throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("x.foo.com") + .addVerifySubjectAltName("abc.test.youtube.com") // should match *.test.youtube.com + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void wildcardSanInPeerCertsVerifiesMultipleVerifySans1() + throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("x.foo.com") + .addVerifySubjectAltName("abc.test.google.fr") // should match *.test.google.fr + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void wildcardSanInPeerCertsSubdomainMismatch() + throws CertificateException, IOException { + // 2. Asterisk (*) cannot match across domain name labels. + // For example, *.example.com matches test.example.com but does not match + // sub.test.example.com. + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("sub.abc.test.youtube.com") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + try { + trustManager.verifySubjectAltNameInChain(certs); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected).hasMessageThat() + .isEqualTo("Peer certificate SAN check failed"); + } + } + + @Test + public void oneIpAddressInPeerCertsVerifies() throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("x.foo.com") + .addVerifySubjectAltName("192.168.1.3") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + trustManager.verifySubjectAltNameInChain(certs); + } + + @Test + public void oneIpAddressInPeerCertsMismatch() throws CertificateException, IOException { + CertificateValidationContext certContext = CertificateValidationContext + .newBuilder() + .addVerifySubjectAltName("x.foo.com") + .addVerifySubjectAltName("192.168.2.3") + .build(); + SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); + X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + try { + trustManager.verifySubjectAltNameInChain(certs); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected).hasMessageThat() + .isEqualTo("Peer certificate SAN check failed"); + } + } +} From ba17682eb28ae9a026b55cf80cad3c73d1f9c1e4 Mon Sep 17 00:00:00 2001 From: Ran Date: Wed, 9 Oct 2019 18:00:45 -0700 Subject: [PATCH 084/131] okhttp: fix header scheme does not match transport type. (#6260) okhttp: fix header scheme does not match transport type. --- .../src/main/java/io/grpc/okhttp/Headers.java | 16 ++++++++--- .../io/grpc/okhttp/OkHttpClientStream.java | 9 ++++++- .../io/grpc/okhttp/OkHttpClientTransport.java | 5 ++++ .../test/java/io/grpc/okhttp/HeadersTest.java | 1 + .../grpc/okhttp/OkHttpClientStreamTest.java | 27 ++++++++++++++++++- .../okhttp/OkHttpClientTransportTest.java | 6 ++--- 6 files changed, 56 insertions(+), 8 deletions(-) diff --git a/okhttp/src/main/java/io/grpc/okhttp/Headers.java b/okhttp/src/main/java/io/grpc/okhttp/Headers.java index cb71846eb00..15008f8040f 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/Headers.java +++ b/okhttp/src/main/java/io/grpc/okhttp/Headers.java @@ -34,7 +34,8 @@ */ class Headers { - public static final Header SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "https"); + public static final Header HTTPS_SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "https"); + public static final Header HTTP_SCHEME_HEADER = new Header(Header.TARGET_SCHEME, "http"); public static final Header METHOD_HEADER = new Header(Header.TARGET_METHOD, GrpcUtil.HTTP_METHOD); public static final Header METHOD_GET_HEADER = new Header(Header.TARGET_METHOD, "GET"); public static final Header CONTENT_TYPE_HEADER = @@ -47,7 +48,12 @@ class Headers { * application thread context. */ public static List
    createRequestHeaders( - Metadata headers, String defaultPath, String authority, String userAgent, boolean useGet) { + Metadata headers, + String defaultPath, + String authority, + String userAgent, + boolean useGet, + boolean usePlaintext) { Preconditions.checkNotNull(headers, "headers"); Preconditions.checkNotNull(defaultPath, "defaultPath"); Preconditions.checkNotNull(authority, "authority"); @@ -61,7 +67,11 @@ public static List
    createRequestHeaders( List
    okhttpHeaders = new ArrayList<>(7 + InternalMetadata.headerCount(headers)); // Set GRPC-specific headers. - okhttpHeaders.add(SCHEME_HEADER); + if (usePlaintext) { + okhttpHeaders.add(HTTP_SCHEME_HEADER); + } else { + okhttpHeaders.add(HTTPS_SCHEME_HEADER); + } if (useGet) { okhttpHeaders.add(METHOD_GET_HEADER); } else { diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java index 2a474faa3a9..b7f298a2fa9 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientStream.java @@ -408,7 +408,14 @@ private void sendBuffer(Buffer buffer, boolean endOfStream, boolean flush) { @GuardedBy("lock") private void streamReady(Metadata metadata, String path) { - requestHeaders = Headers.createRequestHeaders(metadata, path, authority, userAgent, useGet); + requestHeaders = + Headers.createRequestHeaders( + metadata, + path, + authority, + userAgent, + useGet, + transport.isUsingPlaintext()); transport.streamReadyToStart(OkHttpClientStream.this); } diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java index 6244cab6f3e..12181c944c7 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpClientTransport.java @@ -315,6 +315,11 @@ protected void handleNotInUse() { initTransportTracer(); } + // sslSocketFactory is set to null when use plaintext. + boolean isUsingPlaintext() { + return sslSocketFactory == null; + } + private void initTransportTracer() { synchronized (lock) { // to make @GuardedBy linter happy transportTracer.setFlowControlWindowReader(new TransportTracer.FlowControlReader() { diff --git a/okhttp/src/test/java/io/grpc/okhttp/HeadersTest.java b/okhttp/src/test/java/io/grpc/okhttp/HeadersTest.java index bb84a4186bb..e0662b16117 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/HeadersTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/HeadersTest.java @@ -53,6 +53,7 @@ public void createRequestHeaders_sanitizes() { path, authority, userAgent, + false, false); // 7 reserved headers, 1 user header diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java index 8d613026aa6..8590e91829d 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientStreamTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; import com.google.common.io.BaseEncoding; import io.grpc.CallOptions; @@ -182,7 +183,7 @@ public void start_headerFieldOrder() throws IOException { verify(mockedFrameWriter) .synStream(eq(false), eq(false), eq(3), eq(0), headersCaptor.capture()); assertThat(headersCaptor.getValue()).containsExactly( - Headers.SCHEME_HEADER, + Headers.HTTPS_SCHEME_HEADER, Headers.METHOD_HEADER, new Header(Header.TARGET_AUTHORITY, "localhost"), new Header(Header.TARGET_PATH, "/" + methodDescriptor.getFullMethodName()), @@ -192,6 +193,30 @@ public void start_headerFieldOrder() throws IOException { .inOrder(); } + @Test + public void start_headerPlaintext() throws IOException { + Metadata metaData = new Metadata(); + metaData.put(GrpcUtil.USER_AGENT_KEY, "misbehaving-application"); + when(transport.isUsingPlaintext()).thenReturn(true); + stream = new OkHttpClientStream(methodDescriptor, metaData, frameWriter, transport, + flowController, lock, MAX_MESSAGE_SIZE, INITIAL_WINDOW_SIZE, "localhost", + "good-application", StatsTraceContext.NOOP, transportTracer, CallOptions.DEFAULT, false); + stream.start(new BaseClientStreamListener()); + stream.transportState().start(3); + + verify(mockedFrameWriter) + .synStream(eq(false), eq(false), eq(3), eq(0), headersCaptor.capture()); + assertThat(headersCaptor.getValue()).containsExactly( + Headers.HTTP_SCHEME_HEADER, + Headers.METHOD_HEADER, + new Header(Header.TARGET_AUTHORITY, "localhost"), + new Header(Header.TARGET_PATH, "/" + methodDescriptor.getFullMethodName()), + new Header(GrpcUtil.USER_AGENT_KEY.name(), "good-application"), + Headers.CONTENT_TYPE_HEADER, + Headers.TE_HEADER) + .inOrder(); + } + @Test public void getUnaryRequest() throws IOException { MethodDescriptor getMethod = MethodDescriptor.newBuilder() diff --git a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java index b2a63763b76..6f27fec7a2f 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/OkHttpClientTransportTest.java @@ -22,8 +22,8 @@ import static io.grpc.internal.ClientStreamListener.RpcProgress.REFUSED; import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE; import static io.grpc.okhttp.Headers.CONTENT_TYPE_HEADER; +import static io.grpc.okhttp.Headers.HTTP_SCHEME_HEADER; import static io.grpc.okhttp.Headers.METHOD_HEADER; -import static io.grpc.okhttp.Headers.SCHEME_HEADER; import static io.grpc.okhttp.Headers.TE_HEADER; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -650,7 +650,7 @@ public void addDefaultUserAgent() throws Exception { stream.start(listener); Header userAgentHeader = new Header(GrpcUtil.USER_AGENT_KEY.name(), GrpcUtil.getGrpcUserAgent("okhttp", null)); - List
    expectedHeaders = Arrays.asList(SCHEME_HEADER, METHOD_HEADER, + List
    expectedHeaders = Arrays.asList(HTTP_SCHEME_HEADER, METHOD_HEADER, new Header(Header.TARGET_AUTHORITY, "notarealauthority:80"), new Header(Header.TARGET_PATH, "/" + method.getFullMethodName()), userAgentHeader, CONTENT_TYPE_HEADER, TE_HEADER); @@ -667,7 +667,7 @@ public void overrideDefaultUserAgent() throws Exception { OkHttpClientStream stream = clientTransport.newStream(method, new Metadata(), CallOptions.DEFAULT); stream.start(listener); - List
    expectedHeaders = Arrays.asList(SCHEME_HEADER, METHOD_HEADER, + List
    expectedHeaders = Arrays.asList(HTTP_SCHEME_HEADER, METHOD_HEADER, new Header(Header.TARGET_AUTHORITY, "notarealauthority:80"), new Header(Header.TARGET_PATH, "/" + method.getFullMethodName()), new Header(GrpcUtil.USER_AGENT_KEY.name(), From 2c3ef874d858708201060389147470289d86fa9f Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 10 Oct 2019 12:34:45 -0700 Subject: [PATCH 085/131] core: fix typo in AutoConfiguredLoadBalancerFactory (#6262) --- .../io/grpc/internal/AutoConfiguredLoadBalancerFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/grpc/internal/AutoConfiguredLoadBalancerFactory.java b/core/src/main/java/io/grpc/internal/AutoConfiguredLoadBalancerFactory.java index 33afe25f4ea..575994e47eb 100644 --- a/core/src/main/java/io/grpc/internal/AutoConfiguredLoadBalancerFactory.java +++ b/core/src/main/java/io/grpc/internal/AutoConfiguredLoadBalancerFactory.java @@ -273,7 +273,7 @@ PolicySelection decideLoadBalancerProvider( // We don't log the warning every time we have an update. roundRobinDueToGrpclbDepMissing = true; String errorMsg = "Found balancer addresses but grpclb runtime is missing." - + " Will use round_robin. Please include grpc-grpclb in your runtime depedencies."; + + " Will use round_robin. Please include grpc-grpclb in your runtime dependencies."; helper.getChannelLogger().log(ChannelLogLevel.ERROR, errorMsg); logger.warning(errorMsg); } From 316a739e67609e5be171d0b52c1e4d3c9023d360 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Thu, 10 Oct 2019 15:56:47 -0700 Subject: [PATCH 086/131] Revert "all: remove deprecated usePlaintext(boolean)" This reverts commit 296857b4e7a5bb6b5fe367ca6e9ac401dc134a38. --- .../io/grpc/ForwardingChannelBuilder.java | 10 +++++++++ .../java/io/grpc/ManagedChannelBuilder.java | 21 +++++++++++++++++++ .../inprocess/InProcessChannelBuilder.java | 11 ++++++++++ .../io/grpc/cronet/CronetChannelBuilder.java | 8 +++++++ .../io/grpc/netty/NettyChannelBuilder.java | 17 +++++++++++++++ .../io/grpc/okhttp/OkHttpChannelBuilder.java | 16 ++++++++++++++ 6 files changed, 83 insertions(+) diff --git a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java index ab5c3a505b7..db63180f60d 100644 --- a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java +++ b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java @@ -95,6 +95,16 @@ public T overrideAuthority(String authority) { return thisT(); } + /** + * @deprecated use {@link #usePlaintext()} instead. + */ + @Override + @Deprecated + public T usePlaintext(boolean skipNegotiation) { + delegate().usePlaintext(skipNegotiation); + return thisT(); + } + @Override public T usePlaintext() { delegate().usePlaintext(); diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index 7c00cf5dd87..bd07f045b62 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -150,6 +150,27 @@ public static ManagedChannelBuilder forTarget(String target) { */ public abstract T overrideAuthority(String authority); + /** + * Use of a plaintext connection to the server. By default a secure connection mechanism + * such as TLS will be used. + * + *

    Should only be used for testing or for APIs where the use of such API or the data + * exchanged is not sensitive. + * + * @param skipNegotiation @{code true} if there is a priori knowledge that the endpoint supports + * plaintext, {@code false} if plaintext use must be negotiated. + * @deprecated Use {@link #usePlaintext()} instead. + * + * @throws UnsupportedOperationException if plaintext mode is not supported. + * @return this + * @since 1.0.0 + */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1772") + @Deprecated + public T usePlaintext(boolean skipNegotiation) { + throw new UnsupportedOperationException(); + } + /** * Use of a plaintext connection to the server. By default a secure connection mechanism * such as TLS will be used. diff --git a/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java b/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java index 792257758b0..8f8dd42b603 100644 --- a/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java +++ b/core/src/main/java/io/grpc/inprocess/InProcessChannelBuilder.java @@ -94,6 +94,17 @@ public InProcessChannelBuilder useTransportSecurity() { return this; } + /** + * Does nothing. + * + * @deprecated use {@link #usePlaintext()} instead. + */ + @Override + @Deprecated + public InProcessChannelBuilder usePlaintext(boolean skipNegotiation) { + return this; + } + /** * Does nothing. */ diff --git a/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java b/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java index 1a87de58507..2fa71220054 100644 --- a/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java +++ b/cronet/src/main/java/io/grpc/cronet/CronetChannelBuilder.java @@ -127,6 +127,14 @@ public final CronetChannelBuilder alwaysUsePut(boolean enable) { return this; } + /** + * Not supported for building cronet channel. + */ + @Override + public final CronetChannelBuilder usePlaintext(boolean skipNegotiation) { + throw new IllegalArgumentException("Plaintext not currently supported"); + } + /** * Sets {@link android.net.TrafficStats} tag to use when accounting socket traffic caused by this * channel. See {@link android.net.TrafficStats} for more information. If no tag is set (e.g. this diff --git a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java index 3b3da720ea0..84d47b8feee 100644 --- a/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java +++ b/netty/src/main/java/io/grpc/netty/NettyChannelBuilder.java @@ -285,6 +285,23 @@ public NettyChannelBuilder maxInboundMetadataSize(int bytes) { return this; } + /** + * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT} or + * {@code PLAINTEXT_UPGRADE}. + * + * @deprecated use {@link #usePlaintext()} instead. + */ + @Override + @Deprecated + public NettyChannelBuilder usePlaintext(boolean skipNegotiation) { + if (skipNegotiation) { + negotiationType(NegotiationType.PLAINTEXT); + } else { + negotiationType(NegotiationType.PLAINTEXT_UPGRADE); + } + return this; + } + /** * Equivalent to using {@link #negotiationType(NegotiationType)} with {@code PLAINTEXT}. */ diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java index b5352828f34..b8071d9cf62 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java @@ -305,6 +305,22 @@ public final OkHttpChannelBuilder connectionSpec( return this; } + /** + * Equivalent to using {@link #negotiationType} with {@code PLAINTEXT}. + * + * @deprecated use {@link #usePlaintext()} instead. + */ + @Override + @Deprecated + public final OkHttpChannelBuilder usePlaintext(boolean skipNegotiation) { + if (skipNegotiation) { + negotiationType(io.grpc.okhttp.NegotiationType.PLAINTEXT); + } else { + throw new IllegalArgumentException("Plaintext negotiation not currently supported"); + } + return this; + } + /** Sets the negotiation type for the HTTP/2 connection to plaintext. */ @Override public final OkHttpChannelBuilder usePlaintext() { From 0e25cd8e7c892e998c20812a8c3de3b41e03fb49 Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 10 Oct 2019 16:06:17 -0700 Subject: [PATCH 087/131] xds: add private constructor for utility class. (#6270) --- xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java b/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java index 481abd8e635..f51312df29c 100644 --- a/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java +++ b/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java @@ -50,4 +50,6 @@ static synchronized X509Certificate[] toX509Certificates(String fileName) bis.close(); } } + + private CertificateUtils() {} } From a94a63c7ae17683d7d611f8ae34f3f8dd8eda5a6 Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 10 Oct 2019 16:18:09 -0700 Subject: [PATCH 088/131] xds: clean up. (#6271) --- .../java/io/grpc/xds/sds/trust/SdsX509TrustManager.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java b/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java index a1ae0d70db3..c2d4b28593a 100644 --- a/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java +++ b/xds/src/main/java/io/grpc/xds/sds/trust/SdsX509TrustManager.java @@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Ascii; import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; import java.net.Socket; import java.security.cert.CertificateException; @@ -166,7 +167,7 @@ private static boolean verifyDnsNameInSanList(String altNameFromCert, */ private static boolean verifyStringInSanList(String stringFromCert, List verifySanList) { for (String sanToVerify : verifySanList) { - if (sanToVerify.equalsIgnoreCase(stringFromCert)) { + if (Ascii.equalsIgnoreCase(sanToVerify, stringFromCert)) { return true; } } @@ -199,7 +200,7 @@ private static boolean verifyOneSanInList(List entry, List verifySanL private static void verifySubjectAltNameInLeaf(X509Certificate cert, List verifyList) throws CertificateException { Collection> names = cert.getSubjectAlternativeNames(); - if (names == null || names.size() == 0) { + if (names == null || names.isEmpty()) { throw new CertificateException("Peer certificate SAN check failed"); } for (List name : names) { @@ -221,7 +222,7 @@ void verifySubjectAltNameInChain(X509Certificate[] peerCertChain) throws Certifi return; } List verifyList = certContext.getVerifySubjectAltNameList(); - if (verifyList == null || verifyList.isEmpty()) { + if (verifyList.isEmpty()) { return; } if (peerCertChain == null || peerCertChain.length < 1) { From 0c4fc64bf2133d7cde8383ca924a8f518e44d8a8 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Thu, 10 Oct 2019 16:38:27 -0700 Subject: [PATCH 089/131] xds: first installment of SdsProtocolNegotiators with Client and Server builders (#6261) * xds: SdsProtocolNegotiators with Client and Server builders --- .../io/grpc/xds/sds/XdsChannelBuilder.java | 78 ++++++++++ .../io/grpc/xds/sds/XdsServerBuilder.java | 134 ++++++++++++++++++ .../sds/internal/SdsProtocolNegotiators.java | 110 ++++++++++++++ .../grpc/xds/sds/XdsChannelBuilderTest.java | 41 ++++++ .../io/grpc/xds/sds/XdsServerBuilderTest.java | 39 +++++ 5 files changed, 402 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/sds/XdsChannelBuilder.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/XdsServerBuilder.java create mode 100644 xds/src/main/java/io/grpc/xds/sds/internal/SdsProtocolNegotiators.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/XdsChannelBuilderTest.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/XdsServerBuilderTest.java diff --git a/xds/src/main/java/io/grpc/xds/sds/XdsChannelBuilder.java b/xds/src/main/java/io/grpc/xds/sds/XdsChannelBuilder.java new file mode 100644 index 00000000000..682b4012463 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/XdsChannelBuilder.java @@ -0,0 +1,78 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import io.grpc.ExperimentalApi; +import io.grpc.ForwardingChannelBuilder; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.netty.NettyChannelBuilder; +import io.grpc.xds.sds.internal.SdsProtocolNegotiators; +import java.net.SocketAddress; +import javax.annotation.CheckReturnValue; + +/** + * A version of {@link ManagedChannelBuilder} to create xDS managed channels that will use SDS to + * set up SSL with peers. Note, this is not ready to use yet. + */ +@ExperimentalApi("https://github.com/grpc/grpc-java/issues/6268") +public final class XdsChannelBuilder extends ForwardingChannelBuilder { + + private final NettyChannelBuilder delegate; + + private XdsChannelBuilder(NettyChannelBuilder delegate) { + this.delegate = delegate; + SdsProtocolNegotiators.setProtocolNegotiatorFactory(delegate); + } + + /** + * Creates a new builder with the given server address. See {@link + * NettyChannelBuilder#forAddress(SocketAddress)} for more info. + */ + @CheckReturnValue + public static XdsChannelBuilder forAddress(SocketAddress serverAddress) { + return new XdsChannelBuilder(NettyChannelBuilder.forAddress(serverAddress)); + } + + /** + * Creates a new builder with the given host and port. See {@link + * NettyChannelBuilder#forAddress(String, int)} for more info. + */ + @CheckReturnValue + public static XdsChannelBuilder forAddress(String host, int port) { + return new XdsChannelBuilder(NettyChannelBuilder.forAddress(host, port)); + } + + /** + * Creates a new builder with the given target string. See {@link + * NettyChannelBuilder#forTarget(String)} for more info. + */ + @CheckReturnValue + public static XdsChannelBuilder forTarget(String target) { + return new XdsChannelBuilder(NettyChannelBuilder.forTarget(target)); + } + + @Override + protected ManagedChannelBuilder delegate() { + return delegate; + } + + @Override + public ManagedChannel build() { + return delegate.build(); + } +} diff --git a/xds/src/main/java/io/grpc/xds/sds/XdsServerBuilder.java b/xds/src/main/java/io/grpc/xds/sds/XdsServerBuilder.java new file mode 100644 index 00000000000..f596d19cfc8 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/XdsServerBuilder.java @@ -0,0 +1,134 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import io.grpc.BindableService; +import io.grpc.CompressorRegistry; +import io.grpc.DecompressorRegistry; +import io.grpc.ExperimentalApi; +import io.grpc.HandlerRegistry; +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.ServerInterceptor; +import io.grpc.ServerServiceDefinition; +import io.grpc.ServerStreamTracer; +import io.grpc.ServerTransportFilter; +import io.grpc.netty.NettyServerBuilder; +import io.grpc.xds.sds.internal.SdsProtocolNegotiators; +import java.io.File; +import java.net.InetSocketAddress; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; + +/** + * A version of {@link ServerBuilder} to create xDS managed servers that will use SDS to set up SSL + * with peers. Note, this is not ready to use yet. + */ +@ExperimentalApi("https://github.com/grpc/grpc-java/issues/6268") +public final class XdsServerBuilder extends ServerBuilder { + + private final NettyServerBuilder delegate; + + private XdsServerBuilder(NettyServerBuilder nettyDelegate) { + this.delegate = nettyDelegate; + } + + @Override + public XdsServerBuilder handshakeTimeout(long timeout, TimeUnit unit) { + delegate.handshakeTimeout(timeout, unit); + return this; + } + + @Override + public XdsServerBuilder directExecutor() { + delegate.directExecutor(); + return this; + } + + @Override + public XdsServerBuilder addStreamTracerFactory(ServerStreamTracer.Factory factory) { + delegate.addStreamTracerFactory(factory); + return this; + } + + @Override + public XdsServerBuilder addTransportFilter(ServerTransportFilter filter) { + delegate.addTransportFilter(filter); + return this; + } + + @Override + public XdsServerBuilder executor(Executor executor) { + delegate.executor(executor); + return this; + } + + @Override + public XdsServerBuilder addService(ServerServiceDefinition service) { + delegate.addService(service); + return this; + } + + @Override + public XdsServerBuilder addService(BindableService bindableService) { + delegate.addService(bindableService); + return this; + } + + @Override + public XdsServerBuilder fallbackHandlerRegistry(@Nullable HandlerRegistry fallbackRegistry) { + delegate.fallbackHandlerRegistry(fallbackRegistry); + return this; + } + + @Override + public XdsServerBuilder useTransportSecurity(File certChain, File privateKey) { + throw new UnsupportedOperationException("Cannot set security parameters on XdsServerBuilder"); + } + + @Override + public XdsServerBuilder decompressorRegistry(@Nullable DecompressorRegistry registry) { + delegate.decompressorRegistry(registry); + return this; + } + + @Override + public XdsServerBuilder compressorRegistry(@Nullable CompressorRegistry registry) { + delegate.compressorRegistry(registry); + return this; + } + + @Override + public XdsServerBuilder intercept(ServerInterceptor interceptor) { + delegate.intercept(interceptor); + return this; + } + + /** Creates a gRPC server builder for the given port. */ + public static XdsServerBuilder forPort(int port) { + NettyServerBuilder nettyDelegate = NettyServerBuilder.forAddress(new InetSocketAddress(port)); + return new XdsServerBuilder(nettyDelegate); + } + + @Override + public Server build() { + // note: doing it in build() will overwrite any previously set ProtocolNegotiator + delegate.protocolNegotiator(SdsProtocolNegotiators.serverProtocolNegotiator()); + return delegate.build(); + } +} diff --git a/xds/src/main/java/io/grpc/xds/sds/internal/SdsProtocolNegotiators.java b/xds/src/main/java/io/grpc/xds/sds/internal/SdsProtocolNegotiators.java new file mode 100644 index 00000000000..9bc5129ad18 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/internal/SdsProtocolNegotiators.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds.internal; + +import io.grpc.Internal; +import io.grpc.netty.GrpcHttp2ConnectionHandler; +import io.grpc.netty.InternalNettyChannelBuilder; +import io.grpc.netty.InternalNettyChannelBuilder.ProtocolNegotiatorFactory; +import io.grpc.netty.InternalProtocolNegotiator; +import io.grpc.netty.InternalProtocolNegotiator.ProtocolNegotiator; +import io.grpc.netty.NettyChannelBuilder; +import io.netty.channel.ChannelHandler; +import io.netty.util.AsciiString; + +/** + * Provides client and server side gRPC {@link ProtocolNegotiator}s that use SDS to provide the SSL + * context. + */ +@Internal +public final class SdsProtocolNegotiators { + + private static final AsciiString SCHEME = AsciiString.of("https"); + + private static final class ClientSdsProtocolNegotiatorFactory + implements InternalNettyChannelBuilder.ProtocolNegotiatorFactory { + + @Override + public InternalProtocolNegotiator.ProtocolNegotiator buildProtocolNegotiator() { + final ClientSdsProtocolNegotiator negotiator = new ClientSdsProtocolNegotiator(); + final class LocalSdsNegotiator implements InternalProtocolNegotiator.ProtocolNegotiator { + + @Override + public AsciiString scheme() { + return negotiator.scheme(); + } + + @Override + public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler) { + return negotiator.newHandler(grpcHandler); + } + + @Override + public void close() { + negotiator.close(); + } + } + + return new LocalSdsNegotiator(); + } + } + + private static final class ClientSdsProtocolNegotiator implements ProtocolNegotiator { + + @Override + public AsciiString scheme() { + return SCHEME; + } + + @Override + public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler) { + // TODO(sanjaypujare): once implemented return ClientSdsHandler + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override + public void close() {} + } + + private static final class ServerSdsProtocolNegotiator implements ProtocolNegotiator { + + @Override + public AsciiString scheme() { + return SCHEME; + } + + @Override + public ChannelHandler newHandler(GrpcHttp2ConnectionHandler grpcHandler) { + // TODO(sanjaypujare): once implemented return ServerSdsHandler + throw new UnsupportedOperationException("Not implemented yet"); + } + + @Override + public void close() {} + } + + /** Sets the {@link ProtocolNegotiatorFactory} on a NettyChannelBuilder. */ + public static void setProtocolNegotiatorFactory(NettyChannelBuilder builder) { + InternalNettyChannelBuilder.setProtocolNegotiatorFactory( + builder, new ClientSdsProtocolNegotiatorFactory()); + } + + /** Creates an SDS based {@link ProtocolNegotiator} for a server. */ + public static ProtocolNegotiator serverProtocolNegotiator() { + return new ServerSdsProtocolNegotiator(); + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/XdsChannelBuilderTest.java b/xds/src/test/java/io/grpc/xds/sds/XdsChannelBuilderTest.java new file mode 100644 index 00000000000..4789cd8ec40 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/XdsChannelBuilderTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import io.grpc.ManagedChannel; +import io.grpc.netty.NettyChannelBuilder; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link XdsChannelBuilder}. + */ +@RunWith(JUnit4.class) +public class XdsChannelBuilderTest { + + @Test + public void buildsXdsChannelBuilder() { + XdsChannelBuilder builder = XdsChannelBuilder.forTarget("localhost:8080"); + assertThat(builder).isNotNull(); + assertThat(builder.delegate()).isInstanceOf(NettyChannelBuilder.class); + ManagedChannel channel = builder.build(); + assertThat(channel).isNotNull(); + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/XdsServerBuilderTest.java b/xds/src/test/java/io/grpc/xds/sds/XdsServerBuilderTest.java new file mode 100644 index 00000000000..805d073e9ce --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/XdsServerBuilderTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import io.grpc.Server; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** + * Unit tests for {@link XdsChannelBuilder}. + */ +@RunWith(JUnit4.class) +public class XdsServerBuilderTest { + + @Test + public void buildsXdsServerBuilder() { + XdsServerBuilder builder = XdsServerBuilder.forPort(8080); + assertThat(builder).isInstanceOf(XdsServerBuilder.class); + Server server = builder.build(); + assertThat(server).isNotNull(); + } +} From ab092ec43cd69b6ae312815212b6a4adb50ed7c2 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Fri, 11 Oct 2019 11:40:11 -0700 Subject: [PATCH 090/131] xds: disables some tests that break with blaze (#6273) --- .../grpc/xds/sds/trust/SdsX509TrustManagerTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java index d118c7eb2d1..1f557c776c6 100644 --- a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java @@ -25,6 +25,7 @@ import java.security.cert.X509Certificate; import javax.net.ssl.X509ExtendedTrustManager; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,6 +55,7 @@ public class SdsX509TrustManagerTest { @Mock private X509ExtendedTrustManager mockDelegate; + @Ignore("test fails on blaze") @Test public void nullCertContextTest() throws CertificateException, IOException { SdsX509TrustManager trustManager = new SdsX509TrustManager(null, mockDelegate); @@ -61,6 +63,7 @@ public void nullCertContextTest() throws CertificateException, IOException { trustManager.verifySubjectAltNameInChain(certs); } + @Ignore("test fails on blaze") @Test public void emptySanListContextTest() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); @@ -101,6 +104,7 @@ public void emptyArrayPeerCerts() throws CertificateException, FileNotFoundExcep } } + @Ignore("test fails on blaze") @Test public void noSansInPeerCerts() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext @@ -118,6 +122,7 @@ public void noSansInPeerCerts() throws CertificateException, IOException { } } + @Ignore("test fails on blaze") @Test public void oneSanInPeerCertsVerifies() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext @@ -142,6 +147,7 @@ public void oneSanInPeerCertsVerifiesMultipleVerifySans() trustManager.verifySubjectAltNameInChain(certs); } + @Ignore("test fails on blaze") @Test public void oneSanInPeerCertsNotFoundException() throws CertificateException, IOException { @@ -157,6 +163,7 @@ public void oneSanInPeerCertsNotFoundException() } } + @Ignore("test fails on blaze") @Test public void wildcardSanInPeerCertsVerifiesMultipleVerifySans() throws CertificateException, IOException { @@ -170,6 +177,7 @@ public void wildcardSanInPeerCertsVerifiesMultipleVerifySans() trustManager.verifySubjectAltNameInChain(certs); } + @Ignore("test fails on blaze") @Test public void wildcardSanInPeerCertsVerifiesMultipleVerifySans1() throws CertificateException, IOException { @@ -183,6 +191,7 @@ public void wildcardSanInPeerCertsVerifiesMultipleVerifySans1() trustManager.verifySubjectAltNameInChain(certs); } + @Ignore("test fails on blaze") @Test public void wildcardSanInPeerCertsSubdomainMismatch() throws CertificateException, IOException { @@ -204,6 +213,7 @@ public void wildcardSanInPeerCertsSubdomainMismatch() } } + @Ignore("test fails on blaze") @Test public void oneIpAddressInPeerCertsVerifies() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext @@ -216,6 +226,7 @@ public void oneIpAddressInPeerCertsVerifies() throws CertificateException, IOExc trustManager.verifySubjectAltNameInChain(certs); } + @Ignore("test fails on blaze") @Test public void oneIpAddressInPeerCertsMismatch() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext From 58886310e4d61a71ea645d1af3fd25bbf3e837d1 Mon Sep 17 00:00:00 2001 From: Ran Date: Fri, 11 Oct 2019 14:16:47 -0700 Subject: [PATCH 091/131] xds: disable test that break on blaze. (#6275) --- .../test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java index 1f557c776c6..d3e2e5c9728 100644 --- a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java @@ -134,6 +134,7 @@ public void oneSanInPeerCertsVerifies() throws CertificateException, IOException trustManager.verifySubjectAltNameInChain(certs); } + @Ignore("test fails on blaze") @Test public void oneSanInPeerCertsVerifiesMultipleVerifySans() throws CertificateException, IOException { From adcfb3e623d5d946f7b7c5218e0dfeebe99b66de Mon Sep 17 00:00:00 2001 From: Grant Oakley Date: Mon, 14 Oct 2019 08:46:26 -0700 Subject: [PATCH 092/131] api,core: Adds an Executor field to NameResolver.Args. Adds an Executor to NameResolver.Args, which is optionally set on ManagedChannelBuilder. This allows NameResolver implementations to avoid creating their own thread pools if the application already manages its own pools. Addresses #3703. --- .../io/grpc/ForwardingChannelBuilder.java | 6 ++ .../java/io/grpc/ManagedChannelBuilder.java | 17 ++++ api/src/main/java/io/grpc/NameResolver.java | 39 +++++++- .../test/java/io/grpc/NameResolverTest.java | 6 ++ .../AbstractManagedChannelImplBuilder.java | 12 +++ .../io/grpc/internal/DnsNameResolver.java | 14 ++- .../io/grpc/internal/ManagedChannelImpl.java | 34 +++++-- ...AbstractManagedChannelImplBuilderTest.java | 15 +++ .../io/grpc/internal/DnsNameResolverTest.java | 99 +++++++++++++++---- .../grpc/internal/ManagedChannelImplTest.java | 24 ++++- 10 files changed, 229 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java index db63180f60d..4ef944c7ab9 100644 --- a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java +++ b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java @@ -71,6 +71,12 @@ public T executor(Executor executor) { return thisT(); } + @Override + public T blockingExecutor(Executor executor) { + delegate().blockingExecutor(executor); + return thisT(); + } + @Override public T intercept(List interceptors) { delegate().intercept(interceptors); diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index bd07f045b62..e2706e2ec51 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -103,6 +103,23 @@ public static ManagedChannelBuilder forTarget(String target) { */ public abstract T executor(Executor executor); + /** + * Provides a custom executor that will be used for operations that block. + * + *

    It's an optional parameter. If the user has not provided an executor when the channel is + * built, the builder will use a static cached thread pool. + * + *

    The channel won't take ownership of the given executor. It's caller's responsibility to shut + * down the executor when it's desired. + * + * @return this + * @throws UnsupportedOperationException if unsupported + * @since 1.25.0 + */ + public T blockingExecutor(Executor executor) { + throw new UnsupportedOperationException(); + } + /** * Adds interceptors that will be called before the channel performs its real work. This is * functionally equivalent to using {@link ClientInterceptors#intercept(Channel, List)}, but while diff --git a/api/src/main/java/io/grpc/NameResolver.java b/api/src/main/java/io/grpc/NameResolver.java index c96f330c61d..d8c01b6a7c3 100644 --- a/api/src/main/java/io/grpc/NameResolver.java +++ b/api/src/main/java/io/grpc/NameResolver.java @@ -29,6 +29,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.concurrent.Executor; import javax.annotation.Nullable; import javax.annotation.concurrent.ThreadSafe; @@ -411,13 +412,19 @@ public static final class Args { private final ProxyDetector proxyDetector; private final SynchronizationContext syncContext; private final ServiceConfigParser serviceConfigParser; - - Args(Integer defaultPort, ProxyDetector proxyDetector, - SynchronizationContext syncContext, ServiceConfigParser serviceConfigParser) { + @Nullable private final Executor executor; + + Args( + Integer defaultPort, + ProxyDetector proxyDetector, + SynchronizationContext syncContext, + ServiceConfigParser serviceConfigParser, + @Nullable Executor executor) { this.defaultPort = checkNotNull(defaultPort, "defaultPort not set"); this.proxyDetector = checkNotNull(proxyDetector, "proxyDetector not set"); this.syncContext = checkNotNull(syncContext, "syncContext not set"); this.serviceConfigParser = checkNotNull(serviceConfigParser, "serviceConfigParser not set"); + this.executor = executor; } /** @@ -459,6 +466,17 @@ public ServiceConfigParser getServiceConfigParser() { return serviceConfigParser; } + /** + * Returns the Executor on which this resolver should execute long-running or I/O bound work. + * Null if no Executor was set. + * + * @since 1.25.0 + */ + @Nullable + public Executor getBlockingExecutor() { + return executor; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) @@ -466,6 +484,7 @@ public String toString() { .add("proxyDetector", proxyDetector) .add("syncContext", syncContext) .add("serviceConfigParser", serviceConfigParser) + .add("executor", executor) .toString(); } @@ -480,6 +499,7 @@ public Builder toBuilder() { builder.setProxyDetector(proxyDetector); builder.setSynchronizationContext(syncContext); builder.setServiceConfigParser(serviceConfigParser); + builder.setBlockingExecutor(executor); return builder; } @@ -502,6 +522,7 @@ public static final class Builder { private ProxyDetector proxyDetector; private SynchronizationContext syncContext; private ServiceConfigParser serviceConfigParser; + private Executor executor; Builder() { } @@ -546,13 +567,23 @@ public Builder setServiceConfigParser(ServiceConfigParser parser) { return this; } + /** + * See {@link Args#getBlockingExecutor}. This is an optional field. + * + * @since 1.25.0 + */ + public Builder setBlockingExecutor(Executor executor) { + this.executor = executor; + return this; + } + /** * Builds an {@link Args}. * * @since 1.21.0 */ public Args build() { - return new Args(defaultPort, proxyDetector, syncContext, serviceConfigParser); + return new Args(defaultPort, proxyDetector, syncContext, serviceConfigParser, executor); } } } diff --git a/api/src/test/java/io/grpc/NameResolverTest.java b/api/src/test/java/io/grpc/NameResolverTest.java index b641fcac682..09e1e1c20f6 100644 --- a/api/src/test/java/io/grpc/NameResolverTest.java +++ b/api/src/test/java/io/grpc/NameResolverTest.java @@ -29,6 +29,8 @@ import java.net.URI; import java.util.Collections; import java.util.Map; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicReference; import org.junit.Before; import org.junit.Test; @@ -43,6 +45,7 @@ public class NameResolverTest { private final SynchronizationContext syncContext = new SynchronizationContext(mock(UncaughtExceptionHandler.class)); private final ServiceConfigParser parser = mock(ServiceConfigParser.class); + private final Executor executor = Executors.newSingleThreadExecutor(); private URI uri; private final NameResolver nameResolver = mock(NameResolver.class); @@ -58,12 +61,14 @@ public void args() { assertThat(args.getProxyDetector()).isSameInstanceAs(proxyDetector); assertThat(args.getSynchronizationContext()).isSameInstanceAs(syncContext); assertThat(args.getServiceConfigParser()).isSameInstanceAs(parser); + assertThat(args.getBlockingExecutor()).isSameInstanceAs(executor); NameResolver.Args args2 = args.toBuilder().build(); assertThat(args2.getDefaultPort()).isEqualTo(defaultPort); assertThat(args2.getProxyDetector()).isSameInstanceAs(proxyDetector); assertThat(args2.getSynchronizationContext()).isSameInstanceAs(syncContext); assertThat(args2.getServiceConfigParser()).isSameInstanceAs(parser); + assertThat(args2.getBlockingExecutor()).isSameInstanceAs(executor); assertThat(args2).isNotSameInstanceAs(args); assertThat(args2).isNotEqualTo(args); @@ -246,6 +251,7 @@ private NameResolver.Args createArgs() { .setProxyDetector(proxyDetector) .setSynchronizationContext(syncContext) .setServiceConfigParser(parser) + .setBlockingExecutor(executor) .build(); } } diff --git a/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java b/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java index 14417b6b26f..3698eda6fd1 100644 --- a/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java +++ b/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java @@ -95,6 +95,8 @@ public static ManagedChannelBuilder forTarget(String target) { ObjectPool executorPool = DEFAULT_EXECUTOR_POOL; + ObjectPool blockingExecutorPool = DEFAULT_EXECUTOR_POOL; + private final List interceptors = new ArrayList<>(); final NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry(); @@ -217,6 +219,16 @@ public final T executor(Executor executor) { return thisT(); } + @Override + public final T blockingExecutor(Executor executor) { + if (executor != null) { + this.blockingExecutorPool = new FixedObjectPool<>(executor); + } else { + this.blockingExecutorPool = DEFAULT_EXECUTOR_POOL; + } + return thisT(); + } + @Override public final T intercept(List interceptors) { this.interceptors.addAll(interceptors); diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolver.java b/core/src/main/java/io/grpc/internal/DnsNameResolver.java index 0da09299afa..8e07dbdb8ec 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolver.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolver.java @@ -138,6 +138,8 @@ final class DnsNameResolver extends NameResolver { private final String authority; private final String host; private final int port; + + /** Executor that will be used if an Executor is not provide via {@link NameResolver.Args}. */ private final Resource executorResource; private final long cacheTtlNanos; private final SynchronizationContext syncContext; @@ -147,6 +149,10 @@ final class DnsNameResolver extends NameResolver { private ResolutionResults cachedResolutionResults; private boolean shutdown; private Executor executor; + + /** True if using an executor resource that should be released after use. */ + private final boolean usingExecutorResource; + private boolean resolving; // The field must be accessed from syncContext, although the methods on an Listener2 can be called @@ -176,6 +182,8 @@ final class DnsNameResolver extends NameResolver { this.stopwatch = Preconditions.checkNotNull(stopwatch, "stopwatch"); this.syncContext = Preconditions.checkNotNull(args.getSynchronizationContext(), "syncContext"); + this.executor = args.getBlockingExecutor(); + this.usingExecutorResource = executor == null; } @Override @@ -186,7 +194,9 @@ public String getServiceAuthority() { @Override public void start(Listener2 listener) { Preconditions.checkState(this.listener == null, "already started"); - executor = SharedResourceHolder.get(executorResource); + if (usingExecutorResource) { + executor = SharedResourceHolder.get(executorResource); + } this.listener = Preconditions.checkNotNull(listener, "listener"); resolve(); } @@ -361,7 +371,7 @@ public void shutdown() { return; } shutdown = true; - if (executor != null) { + if (executor != null && usingExecutorResource) { executor = SharedResourceHolder.release(executorResource, executor); } } diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index 7e6ca957057..fed1d660bc9 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -142,6 +142,7 @@ final class ManagedChannelImpl extends ManagedChannel implements private final ObjectPool executorPool; private final ObjectPool balancerRpcExecutorPool; private final ExecutorHolder balancerRpcExecutorHolder; + private final ExecutorHolder blockingExecutorHolder; private final TimeProvider timeProvider; private final int maxTraceEvents; @@ -565,16 +566,30 @@ ClientStream newSubstream(ClientStreamTracer.Factory tracerFactory, Metadata new builder.proxyDetector != null ? builder.proxyDetector : GrpcUtil.DEFAULT_PROXY_DETECTOR; this.retryEnabled = builder.retryEnabled && !builder.temporarilyDisableRetry; this.loadBalancerFactory = new AutoConfiguredLoadBalancerFactory(builder.defaultLbPolicy); + this.blockingExecutorHolder = + new ExecutorHolder( + checkNotNull(builder.blockingExecutorPool, "blockingExecutorPool")); this.nameResolverRegistry = builder.nameResolverRegistry; - this.nameResolverArgs = NameResolver.Args.newBuilder() - .setDefaultPort(builder.getDefaultPort()) - .setProxyDetector(proxyDetector) - .setSynchronizationContext(syncContext) - .setServiceConfigParser( - new ScParser( - retryEnabled, builder.maxRetryAttempts, builder.maxHedgedAttempts, - loadBalancerFactory)) - .build(); + this.nameResolverArgs = + NameResolver.Args.newBuilder() + .setDefaultPort(builder.getDefaultPort()) + .setProxyDetector(proxyDetector) + .setSynchronizationContext(syncContext) + .setServiceConfigParser( + new ScParser( + retryEnabled, + builder.maxRetryAttempts, + builder.maxHedgedAttempts, + loadBalancerFactory)) + .setBlockingExecutor( + // Avoid creating the blockingExecutor until it is first used + new Executor() { + @Override + public void execute(Runnable command) { + blockingExecutorHolder.getExecutor().execute(command); + } + }) + .build(); this.nameResolver = getNameResolver(target, nameResolverFactory, nameResolverArgs); this.timeProvider = checkNotNull(timeProvider, "timeProvider"); maxTraceEvents = builder.maxTraceEvents; @@ -885,6 +900,7 @@ private void maybeTerminateChannel() { terminatedLatch.countDown(); executorPool.returnObject(executor); balancerRpcExecutorHolder.release(); + blockingExecutorHolder.release(); // Release the transport factory so that it can deallocate any resources. transportFactory.close(); } diff --git a/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java b/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java index 4b4adcc7e55..fee1685f8a2 100644 --- a/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java +++ b/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java @@ -99,6 +99,21 @@ public void directExecutor() { assertEquals(MoreExecutors.directExecutor(), builder.executorPool.getObject()); } + @Test + public void blockingExecutor_normal() { + Executor executor = mock(Executor.class); + assertEquals(builder, builder.blockingExecutor(executor)); + assertEquals(executor, builder.blockingExecutorPool.getObject()); + } + + @Test + public void blockingExecutor_null() { + ObjectPool defaultValue = builder.blockingExecutorPool; + builder.blockingExecutor(mock(Executor.class)); + assertEquals(builder, builder.blockingExecutor(null)); + assertEquals(defaultValue, builder.blockingExecutorPool); + } + @Test public void nameResolverFactory_default() { assertNotNull(builder.getNameResolverFactory()); diff --git a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java index 361ee69de3c..7214db6edac 100644 --- a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java +++ b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java @@ -70,6 +70,7 @@ import java.util.Random; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; @@ -120,17 +121,20 @@ public void uncaughtException(Thread t, Throwable e) { private final FakeClock fakeClock = new FakeClock(); private final FakeClock fakeExecutor = new FakeClock(); - private final Resource fakeExecutorResource = - new Resource() { - @Override - public Executor create() { - return fakeExecutor.getScheduledExecutorService(); - } + private final FakeExecutorResource fakeExecutorResource = new FakeExecutorResource(); - @Override - public void close(Executor instance) { - } - }; + private final class FakeExecutorResource implements Resource { + private final AtomicInteger createCount = new AtomicInteger(); + + @Override + public Executor create() { + createCount.incrementAndGet(); + return fakeExecutor.getScheduledExecutorService(); + } + + @Override + public void close(Executor instance) {} + } @Mock private NameResolver.Listener2 mockListener; @@ -165,18 +169,20 @@ private DnsNameResolver newResolver( final ProxyDetector proxyDetector, Stopwatch stopwatch, boolean isAndroid) { - DnsNameResolver dnsResolver = new DnsNameResolver( - null, - name, + NameResolver.Args args = NameResolver.Args.newBuilder() .setDefaultPort(defaultPort) .setProxyDetector(proxyDetector) .setSynchronizationContext(syncContext) .setServiceConfigParser(mock(ServiceConfigParser.class)) - .build(), - fakeExecutorResource, - stopwatch, - isAndroid); + .build(); + return newResolver(name, stopwatch, isAndroid, args); + } + + private DnsNameResolver newResolver( + String name, Stopwatch stopwatch, boolean isAndroid, NameResolver.Args args) { + DnsNameResolver dnsResolver = + new DnsNameResolver(null, name, args, fakeExecutorResource, stopwatch, isAndroid); // By default, using the mocked ResourceResolver to avoid I/O dnsResolver.setResourceResolver(new JndiResourceResolver(recordFetcher)); return dnsResolver; @@ -293,6 +299,65 @@ private void resolveNeverCache(boolean isAndroid) throws Exception { verify(mockResolver, times(2)).resolveAddress(anyString()); } + @Test + public void testExecutor_default() throws Exception { + final List answer = createAddressList(2); + + DnsNameResolver resolver = newResolver("foo.googleapis.com", 81); + AddressResolver mockResolver = mock(AddressResolver.class); + when(mockResolver.resolveAddress(anyString())).thenReturn(answer); + resolver.setAddressResolver(mockResolver); + + resolver.start(mockListener); + assertEquals(1, fakeExecutor.runDueTasks()); + verify(mockListener).onResult(resultCaptor.capture()); + assertAnswerMatches(answer, 81, resultCaptor.getValue()); + assertEquals(0, fakeClock.numPendingTasks()); + + resolver.shutdown(); + + assertThat(fakeExecutorResource.createCount.get()).isEqualTo(1); + } + + @Test + public void testExecutor_custom() throws Exception { + final List answer = createAddressList(2); + final AtomicInteger executions = new AtomicInteger(); + + NameResolver.Args args = + NameResolver.Args.newBuilder() + .setDefaultPort(81) + .setProxyDetector(GrpcUtil.NOOP_PROXY_DETECTOR) + .setSynchronizationContext(syncContext) + .setServiceConfigParser(mock(ServiceConfigParser.class)) + .setBlockingExecutor( + new Executor() { + @Override + public void execute(Runnable command) { + executions.incrementAndGet(); + command.run(); + } + }) + .build(); + + DnsNameResolver resolver = + newResolver("foo.googleapis.com", Stopwatch.createUnstarted(), false, args); + AddressResolver mockResolver = mock(AddressResolver.class); + when(mockResolver.resolveAddress(anyString())).thenReturn(answer); + resolver.setAddressResolver(mockResolver); + + resolver.start(mockListener); + assertEquals(0, fakeExecutor.runDueTasks()); + verify(mockListener).onResult(resultCaptor.capture()); + assertAnswerMatches(answer, 81, resultCaptor.getValue()); + assertEquals(0, fakeClock.numPendingTasks()); + + resolver.shutdown(); + + assertThat(fakeExecutorResource.createCount.get()).isEqualTo(0); + assertThat(executions.get()).isEqualTo(1); + } + @Test public void resolveAll_failsOnEmptyResult() { DnsNameResolver nr = newResolver("dns:///addr.fake:1234", 443); diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index 3fb9dfea0bc..b2eb58dc108 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -265,6 +265,8 @@ public String getPolicyName() { private ObjectPool balancerRpcExecutorPool; @Mock private CallCredentials creds; + @Mock + private Executor blockingExecutor; private ChannelBuilder channelBuilder; private boolean requestConnection = true; private BlockingQueue transports; @@ -319,11 +321,14 @@ public void setUp() throws Exception { when(balancerRpcExecutorPool.getObject()) .thenReturn(balancerRpcExecutor.getScheduledExecutorService()); - channelBuilder = new ChannelBuilder() - .nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build()) - .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) - .userAgent(USER_AGENT) - .idleTimeout(AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS); + channelBuilder = + new ChannelBuilder() + .nameResolverFactory(new FakeNameResolverFactory.Builder(expectedUri).build()) + .defaultLoadBalancingPolicy(MOCK_POLICY_NAME) + .userAgent(USER_AGENT) + .idleTimeout( + AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS) + .blockingExecutor(blockingExecutor); channelBuilder.executorPool = executorPool; channelBuilder.binlog = null; channelBuilder.channelz = channelz; @@ -3582,6 +3587,15 @@ public String getDefaultScheme() { assertThat(args).isNotNull(); assertThat(args.getDefaultPort()).isEqualTo(DEFAULT_PORT); assertThat(args.getProxyDetector()).isSameInstanceAs(neverProxy); + + verify(blockingExecutor, never()).execute(any(Runnable.class)); + args.getBlockingExecutor() + .execute( + new Runnable() { + @Override + public void run() {} + }); + verify(blockingExecutor, times(1)).execute(any(Runnable.class)); } @Test From eda5e2e32c1f80af8631db6fecf0341b40b09692 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Tue, 15 Oct 2019 08:49:08 -0700 Subject: [PATCH 093/131] protobuf: StatusProto#fromStatusAndTrailers fall-back use status (#6278) --- .../java/io/grpc/protobuf/StatusProto.java | 20 +++++++++++----- .../io/grpc/protobuf/StatusProtoTest.java | 23 +++++++++++-------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java b/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java index 2648138b93b..988e1938af0 100644 --- a/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java +++ b/protobuf/src/main/java/io/grpc/protobuf/StatusProto.java @@ -147,14 +147,16 @@ public static com.google.rpc.Status fromThrowable(Throwable t) { } /** - * Extracts the google.rpc.Status from trailers, and makes sure they match the gRPC - * {@code status}. + * Extracts the {@code google.rpc.Status} from trailers, and makes sure they match the gRPC + * {@code status}. If the trailers do not contain a {@code google.rpc.Status}, it uses + * {@code status} param to generate a {@code google.rpc.Status}. * - * @return the embedded google.rpc.Status or {@code null} if it is not present. + * @return the embedded google.rpc.Status * @since 1.11.0 */ - @Nullable - public static com.google.rpc.Status fromStatusAndTrailers(Status status, Metadata trailers) { + public static com.google.rpc.Status fromStatusAndTrailers( + Status status, @Nullable Metadata trailers) { + checkNotNull(status, "status"); if (trailers != null) { com.google.rpc.Status statusProto = trailers.get(STATUS_DETAILS_KEY); if (statusProto != null) { @@ -164,6 +166,12 @@ public static com.google.rpc.Status fromStatusAndTrailers(Status status, Metadat return statusProto; } } - return null; + // fall-back to status, this is useful if the error is local. e.g. Server is unavailable. + com.google.rpc.Status.Builder statusBuilder = com.google.rpc.Status.newBuilder() + .setCode(status.getCode().value()); + if (status.getDescription() != null) { + statusBuilder.setMessage(status.getDescription()); + } + return statusBuilder.build(); } } diff --git a/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java b/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java index f981236523a..cf9c2c564ab 100644 --- a/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java +++ b/protobuf/src/test/java/io/grpc/protobuf/StatusProtoTest.java @@ -126,20 +126,25 @@ public void toStatusException_shouldThrowIfStatusCodeInvalid() throws Exception } @Test - public void fromThrowable_shouldReturnNullIfTrailersAreNull() { - Status status = Status.fromCodeValue(0); + public void fromThrowable_runtimeException_shouldReturnDerivedStatusIfTrailersAreNull() { + Status status = Status.UNAVAILABLE.withDescription("not available"); - assertNull(StatusProto.fromThrowable(status.asRuntimeException())); - assertNull(StatusProto.fromThrowable(status.asException())); + com.google.rpc.Status statusFromThrowable = + StatusProto.fromThrowable(status.asRuntimeException()); + + assertEquals(statusFromThrowable.getCode(), status.getCode().value()); + assertEquals(statusFromThrowable.getMessage(), status.getDescription()); } @Test - public void fromThrowable_shouldReturnNullIfStatusDetailsKeyIsMissing() { - Status status = Status.fromCodeValue(0); - Metadata emptyMetadata = new Metadata(); + public void fromThrowable_exception_shouldReturnDerivedStatusIfTrailersAreNull() { + Status status = Status.UNAVAILABLE.withDescription("not available"); + + com.google.rpc.Status statusFromThrowable = + StatusProto.fromThrowable(status.asException()); - assertNull(StatusProto.fromThrowable(status.asRuntimeException(emptyMetadata))); - assertNull(StatusProto.fromThrowable(status.asException(emptyMetadata))); + assertEquals(statusFromThrowable.getCode(), status.getCode().value()); + assertEquals(statusFromThrowable.getMessage(), status.getDescription()); } @Test From ddaf1c8ce96a99da01a3915d5a84c6efd9c09bea Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Tue, 15 Oct 2019 17:32:45 -0400 Subject: [PATCH 094/131] xds: fix to use the resource based TestUtils.loadCert (#6281) --- .../grpc/xds/sds/trust/CertificateUtils.java | 10 +- xds/src/test/certs/client.pem | 18 --- xds/src/test/certs/server1.pem | 16 --- .../sds/trust/SdsX509TrustManagerTest.java | 120 ++++++++---------- 4 files changed, 61 insertions(+), 103 deletions(-) delete mode 100644 xds/src/test/certs/client.pem delete mode 100644 xds/src/test/certs/server1.pem diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java b/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java index f51312df29c..805f2039a3b 100644 --- a/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java +++ b/xds/src/main/java/io/grpc/xds/sds/trust/CertificateUtils.java @@ -17,6 +17,7 @@ package io.grpc.xds.sds.trust; import java.io.BufferedInputStream; +import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.cert.Certificate; @@ -38,10 +39,15 @@ private static synchronized void initInstance() throws CertificateException { } } - static synchronized X509Certificate[] toX509Certificates(String fileName) + /** + * Generates X509Certificate array from a file on disk. + * + * @param file a {@link File} containing the cert data + */ + static synchronized X509Certificate[] toX509Certificates(File file) throws CertificateException, IOException { initInstance(); - FileInputStream fis = new FileInputStream(fileName); + FileInputStream fis = new FileInputStream(file); BufferedInputStream bis = new BufferedInputStream(fis); try { Collection certs = factory.generateCertificates(bis); diff --git a/xds/src/test/certs/client.pem b/xds/src/test/certs/client.pem deleted file mode 100644 index 913649b97fb..00000000000 --- a/xds/src/test/certs/client.pem +++ /dev/null @@ -1,18 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC6TCCAlKgAwIBAgIBCjANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTEwMDEwOTU4WhcNMjUxMTA3 -MDEwOTU4WjBaMQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8G -A1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYDVQQDDAp0ZXN0Y2xp -ZW50MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDsVEfbob4W3lVCDLOVmx9K -cdJnoZdvurGaTY87xNiopmaR8zCR7pFR9BX5L4bNG/PkuVLfVTVAKndyDCQggBBr -UTaEITNbfWK9swHJEr20WnKfhS/wo/Xg5sqNNCrFRmnnnwOA4eDlvmYZEzSnJXV6 -pEro9bBH9uOCWWLqmaev7QIDAQABo4HCMIG/MAkGA1UdEwQCMAAwCwYDVR0PBAQD -AgXgMB0GA1UdDgQWBBQAdbW5Vml/CnYwqdP3mOHDARU+8zBwBgNVHSMEaTBnoVqk -WDBWMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMY -SW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2GCCQCRxhke -HRoqBzAJBgNVHREEAjAAMAkGA1UdEgQCMAAwDQYJKoZIhvcNAQELBQADgYEAf4MM -k+sdzd720DfrQ0PF2gDauR3M9uBubozDuMuF6ufAuQBJSKGQEGibXbUelrwHmnql -UjTyfolVcxEBVaF4VFHmn7u6vP7S1NexIDdNUHcULqxIb7Tzl8JYq8OOHD2rQy4H -s8BXaVIzw4YcaCGAMS0iDX052Sy7e2JhP8Noxvo= ------END CERTIFICATE----- diff --git a/xds/src/test/certs/server1.pem b/xds/src/test/certs/server1.pem deleted file mode 100644 index f3d43fcc5be..00000000000 --- a/xds/src/test/certs/server1.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx -MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 -ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco -LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg -zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd -9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw -CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy -em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G -CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 -hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh -y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 ------END CERTIFICATE----- diff --git a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java index d3e2e5c9728..e6276120628 100644 --- a/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/trust/SdsX509TrustManagerTest.java @@ -19,13 +19,13 @@ import static com.google.common.truth.Truth.assertThat; import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.grpc.internal.testing.TestUtils; import java.io.FileNotFoundException; import java.io.IOException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.X509ExtendedTrustManager; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -39,15 +39,12 @@ */ @RunWith(JUnit4.class) public class SdsX509TrustManagerTest { - /** - * server1 has 4 SANs. - */ - private static final String SERVER_1_PEM_FILE = "src/test/certs/server1.pem"; - /** - * client has no SANs. - */ - private static final String CLIENT_PEM_FILE = "src/test/certs/client.pem"; + /** server1 has 4 SANs. */ + private static final String SERVER_1_PEM_FILE = "server1.pem"; + + /** client has no SANs. */ + private static final String CLIENT_PEM_FILE = "client.pem"; @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); @@ -55,86 +52,76 @@ public class SdsX509TrustManagerTest { @Mock private X509ExtendedTrustManager mockDelegate; - @Ignore("test fails on blaze") @Test public void nullCertContextTest() throws CertificateException, IOException { SdsX509TrustManager trustManager = new SdsX509TrustManager(null, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } - @Ignore("test fails on blaze") @Test public void emptySanListContextTest() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } @Test public void missingPeerCerts() throws CertificateException, FileNotFoundException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() - .addVerifySubjectAltName("foo.com") - .build(); + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder().addVerifySubjectAltName("foo.com").build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); try { trustManager.verifySubjectAltNameInChain(null); Assert.fail("no exception thrown"); } catch (CertificateException expected) { - assertThat(expected).hasMessageThat() - .isEqualTo("Peer certificate(s) missing"); + assertThat(expected).hasMessageThat().isEqualTo("Peer certificate(s) missing"); } } @Test public void emptyArrayPeerCerts() throws CertificateException, FileNotFoundException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() - .addVerifySubjectAltName("foo.com") - .build(); + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder().addVerifySubjectAltName("foo.com").build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); try { trustManager.verifySubjectAltNameInChain(new X509Certificate[0]); Assert.fail("no exception thrown"); } catch (CertificateException expected) { - assertThat(expected).hasMessageThat() - .isEqualTo("Peer certificate(s) missing"); + assertThat(expected).hasMessageThat().isEqualTo("Peer certificate(s) missing"); } } - @Ignore("test fails on blaze") @Test public void noSansInPeerCerts() throws CertificateException, IOException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() - .addVerifySubjectAltName("foo.com") - .build(); + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder().addVerifySubjectAltName("foo.com").build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(CLIENT_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(CLIENT_PEM_FILE)); try { trustManager.verifySubjectAltNameInChain(certs); Assert.fail("no exception thrown"); } catch (CertificateException expected) { - assertThat(expected).hasMessageThat() - .isEqualTo("Peer certificate SAN check failed"); + assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed"); } } - @Ignore("test fails on blaze") @Test public void oneSanInPeerCertsVerifies() throws CertificateException, IOException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() .addVerifySubjectAltName("waterzooi.test.google.be") .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } - @Ignore("test fails on blaze") @Test public void oneSanInPeerCertsVerifiesMultipleVerifySans() throws CertificateException, IOException { @@ -144,18 +131,19 @@ public void oneSanInPeerCertsVerifiesMultipleVerifySans() .addVerifySubjectAltName("waterzooi.test.google.be") .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } - @Ignore("test fails on blaze") @Test public void oneSanInPeerCertsNotFoundException() throws CertificateException, IOException { CertificateValidationContext certContext = CertificateValidationContext.newBuilder().addVerifySubjectAltName("x.foo.com").build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); try { trustManager.verifySubjectAltNameInChain(certs); Assert.fail("no exception thrown"); @@ -164,85 +152,83 @@ public void oneSanInPeerCertsNotFoundException() } } - @Ignore("test fails on blaze") @Test public void wildcardSanInPeerCertsVerifiesMultipleVerifySans() throws CertificateException, IOException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() .addVerifySubjectAltName("x.foo.com") - .addVerifySubjectAltName("abc.test.youtube.com") // should match *.test.youtube.com + .addVerifySubjectAltName("abc.test.youtube.com") // should match *.test.youtube.com .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } - @Ignore("test fails on blaze") @Test public void wildcardSanInPeerCertsVerifiesMultipleVerifySans1() throws CertificateException, IOException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() .addVerifySubjectAltName("x.foo.com") - .addVerifySubjectAltName("abc.test.google.fr") // should match *.test.google.fr + .addVerifySubjectAltName("abc.test.google.fr") // should match *.test.google.fr .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } - @Ignore("test fails on blaze") @Test public void wildcardSanInPeerCertsSubdomainMismatch() throws CertificateException, IOException { // 2. Asterisk (*) cannot match across domain name labels. // For example, *.example.com matches test.example.com but does not match // sub.test.example.com. - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() .addVerifySubjectAltName("sub.abc.test.youtube.com") .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); try { trustManager.verifySubjectAltNameInChain(certs); Assert.fail("no exception thrown"); } catch (CertificateException expected) { - assertThat(expected).hasMessageThat() - .isEqualTo("Peer certificate SAN check failed"); + assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed"); } } - @Ignore("test fails on blaze") @Test public void oneIpAddressInPeerCertsVerifies() throws CertificateException, IOException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() .addVerifySubjectAltName("x.foo.com") .addVerifySubjectAltName("192.168.1.3") .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); trustManager.verifySubjectAltNameInChain(certs); } - @Ignore("test fails on blaze") @Test public void oneIpAddressInPeerCertsMismatch() throws CertificateException, IOException { - CertificateValidationContext certContext = CertificateValidationContext - .newBuilder() + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() .addVerifySubjectAltName("x.foo.com") .addVerifySubjectAltName("192.168.2.3") .build(); SdsX509TrustManager trustManager = new SdsX509TrustManager(certContext, mockDelegate); - X509Certificate[] certs = CertificateUtils.toX509Certificates(SERVER_1_PEM_FILE); + X509Certificate[] certs = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); try { trustManager.verifySubjectAltNameInChain(certs); Assert.fail("no exception thrown"); } catch (CertificateException expected) { - assertThat(expected).hasMessageThat() - .isEqualTo("Peer certificate SAN check failed"); + assertThat(expected).hasMessageThat().isEqualTo("Peer certificate SAN check failed"); } } } From fa45a71ec91f237e10eee903256ee2fc3c714bbd Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 16 Oct 2019 09:06:47 -0700 Subject: [PATCH 095/131] api: Allow streaming methods to be safe --- api/src/main/java/io/grpc/MethodDescriptor.java | 2 -- api/src/test/java/io/grpc/MethodDescriptorTest.java | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/api/src/main/java/io/grpc/MethodDescriptor.java b/api/src/main/java/io/grpc/MethodDescriptor.java index a05dd4a77bc..f88e62afd7e 100644 --- a/api/src/main/java/io/grpc/MethodDescriptor.java +++ b/api/src/main/java/io/grpc/MethodDescriptor.java @@ -234,8 +234,6 @@ private MethodDescriptor( this.idempotent = idempotent; this.safe = safe; this.sampledToLocalTracing = sampledToLocalTracing; - Preconditions.checkArgument(!safe || type == MethodType.UNARY, - "Only unary methods can be specified safe"); } /** diff --git a/api/src/test/java/io/grpc/MethodDescriptorTest.java b/api/src/test/java/io/grpc/MethodDescriptorTest.java index f9b00ba8acf..66fcfb670a3 100644 --- a/api/src/test/java/io/grpc/MethodDescriptorTest.java +++ b/api/src/test/java/io/grpc/MethodDescriptorTest.java @@ -102,8 +102,9 @@ public void safeAndNonUnary() { .setResponseMarshaller(new StringMarshaller()) .build(); - thrown.expect(IllegalArgumentException.class); - MethodDescriptor unused = descriptor.toBuilder().setSafe(true).build(); + // Verify it does not throw + MethodDescriptor newDescriptor = descriptor.toBuilder().setSafe(true).build(); + assertTrue(newDescriptor.isSafe()); } @Test From 372945fde53f8a33f92b8b69cfbe1f8984947e07 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 16 Oct 2019 09:59:54 -0700 Subject: [PATCH 096/131] travis: Upgrade from trusty to xenial In 97cb0554 we pinned ourselves to trusty to workaround temporary Java 8 issues. Oracle JDK 8 is "dead" across the ecosystem because Oracle removed download links to it, so we swap to openjdk 8 as we have done elsewhere. OpenJDK 8 is supported with xenial, so we can upgrade. Unfortunately bionic on Travis does not include openjdk8, so we will be unable to easily upgrade to newer versions of the distro unless we drop JDK 8 compilation or we figure out a way to get it working. For example, in may be possible to install the openjdk-8-jdk package. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f62dd95cc4..c80ca705347 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,10 +41,10 @@ after_success: os: - linux -dist: trusty +dist: xenial jdk: - - oraclejdk8 + - openjdk8 - openjdk11 notifications: From 9f0f2a3c8559689b29ea95ee1e7536ed8111cc83 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Fri, 11 Oct 2019 15:43:05 -0700 Subject: [PATCH 097/131] bazel: Add compatibility for --incompatible_load_cc_rules_from_bzl --- compiler/BUILD.bazel | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/BUILD.bazel b/compiler/BUILD.bazel index a87c8307649..f88075c0e09 100644 --- a/compiler/BUILD.bazel +++ b/compiler/BUILD.bazel @@ -1,3 +1,4 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary") load("//:java_grpc_library.bzl", "java_rpc_toolchain") # This should not generally be referenced. Users should use java_grpc_library @@ -8,10 +9,10 @@ cc_binary( "src/java_plugin/cpp/java_generator.h", "src/java_plugin/cpp/java_plugin.cpp", ], + visibility = ["//visibility:public"], deps = [ "@com_google_protobuf//:protoc_lib", ], - visibility = ["//visibility:public"], ) java_library( From 3ce5df3f78e8fd4a619a791914087dd4c0562835 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Wed, 16 Oct 2019 09:19:03 -0700 Subject: [PATCH 098/131] api: Safe implies idempotent --- api/src/main/java/io/grpc/MethodDescriptor.java | 12 +++++++++--- .../test/java/io/grpc/MethodDescriptorTest.java | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/io/grpc/MethodDescriptor.java b/api/src/main/java/io/grpc/MethodDescriptor.java index f88e62afd7e..105db29e561 100644 --- a/api/src/main/java/io/grpc/MethodDescriptor.java +++ b/api/src/main/java/io/grpc/MethodDescriptor.java @@ -224,7 +224,7 @@ private MethodDescriptor( boolean idempotent, boolean safe, boolean sampledToLocalTracing) { - + assert !safe || idempotent : "safe should imply idempotent"; this.type = Preconditions.checkNotNull(type, "type"); this.fullMethodName = Preconditions.checkNotNull(fullMethodName, "fullMethodName"); this.serviceName = extractFullServiceName(fullMethodName); @@ -534,25 +534,31 @@ public Builder setSchemaDescriptor(@Nullable Object schemaDescripto /** * Sets whether the method is idempotent. If true, calling this method more than once doesn't - * have additional side effects. + * have additional side effects. If {@code false}, method is also not safe. * * @since 1.1.0 */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") public Builder setIdempotent(boolean idempotent) { this.idempotent = idempotent; + if (!idempotent) { + this.safe = false; + } return this; } /** * Sets whether this method is safe. If true, calling this method any number of times doesn't - * have side effects. + * have side effects. If {@code true}, method is also idempotent. * * @since 1.1.0 */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") public Builder setSafe(boolean safe) { this.safe = safe; + if (safe) { + this.idempotent = true; + } return this; } diff --git a/api/src/test/java/io/grpc/MethodDescriptorTest.java b/api/src/test/java/io/grpc/MethodDescriptorTest.java index 66fcfb670a3..68637648ce4 100644 --- a/api/src/test/java/io/grpc/MethodDescriptorTest.java +++ b/api/src/test/java/io/grpc/MethodDescriptorTest.java @@ -93,6 +93,22 @@ public void safe() { assertEquals("package.service/method", newDescriptor.getFullMethodName()); } + @Test + public void safeImpliesIdempotent() { + MethodDescriptor descriptor = MethodDescriptor.newBuilder() + .setType(MethodType.UNARY) + .setFullMethodName("package.service/method") + .setRequestMarshaller(new StringMarshaller()) + .setResponseMarshaller(new StringMarshaller()) + .setSafe(true) + .build(); + assertTrue(descriptor.isSafe()); + assertTrue(descriptor.isIdempotent()); + descriptor = descriptor.toBuilder().setIdempotent(false).build(); + assertFalse(descriptor.isSafe()); + assertFalse(descriptor.isIdempotent()); + } + @Test public void safeAndNonUnary() { MethodDescriptor descriptor = MethodDescriptor.newBuilder() From 9eca2dcc4f31cc606e571def4efde8c0f7cb0b63 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Tue, 15 Oct 2019 08:26:21 -0700 Subject: [PATCH 099/131] api: Add ExperimentalApi annotations for blockingExecutor These should have been present when initially added in #6238, but we forgot. --- api/src/main/java/io/grpc/ManagedChannelBuilder.java | 1 + api/src/main/java/io/grpc/NameResolver.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index e2706e2ec51..cfb626b6648 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -116,6 +116,7 @@ public static ManagedChannelBuilder forTarget(String target) { * @throws UnsupportedOperationException if unsupported * @since 1.25.0 */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") public T blockingExecutor(Executor executor) { throw new UnsupportedOperationException(); } diff --git a/api/src/main/java/io/grpc/NameResolver.java b/api/src/main/java/io/grpc/NameResolver.java index d8c01b6a7c3..459f74fe50c 100644 --- a/api/src/main/java/io/grpc/NameResolver.java +++ b/api/src/main/java/io/grpc/NameResolver.java @@ -473,6 +473,7 @@ public ServiceConfigParser getServiceConfigParser() { * @since 1.25.0 */ @Nullable + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") public Executor getBlockingExecutor() { return executor; } @@ -572,6 +573,7 @@ public Builder setServiceConfigParser(ServiceConfigParser parser) { * * @since 1.25.0 */ + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") public Builder setBlockingExecutor(Executor executor) { this.executor = executor; return this; From 4fc41bd0e1353ccb84f4d466611977bd1ddec42f Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Wed, 16 Oct 2019 14:35:49 -0700 Subject: [PATCH 100/131] xds: SdsTrustManagerFactory implementation - uses SdsX509TrustManager (#6267) --- .../xds/sds/trust/SdsTrustManagerFactory.java | 115 +++++++++++++++ .../sds/trust/SdsTrustManagerFactoryTest.java | 132 ++++++++++++++++++ 2 files changed, 247 insertions(+) create mode 100644 xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java b/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java new file mode 100644 index 00000000000..0b19721beb1 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java @@ -0,0 +1,115 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds.trust; + +import static com.google.common.base.Preconditions.checkNotNull; + +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.grpc.Internal; +import io.netty.handler.ssl.util.SimpleTrustManagerFactory; +import java.io.File; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; +import javax.net.ssl.ManagerFactoryParameters; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedTrustManager; + +/** + * Factory class used by providers of {@link io.grpc.xds.sds.TlsContextManager} to provide a {@link + * SdsX509TrustManager} for trust and SAN checks. + */ +@Internal +public final class SdsTrustManagerFactory extends SimpleTrustManagerFactory { + + private static final Logger logger = Logger.getLogger(SdsTrustManagerFactory.class.getName()); + private SdsX509TrustManager sdsX509TrustManager; + + /** Constructor that loads certs from a file. */ + public SdsTrustManagerFactory( + String certsFile, @Nullable CertificateValidationContext certContext) + throws CertificateException, IOException, CertStoreException { + this(CertificateUtils.toX509Certificates(new File(certsFile)), certContext); + } + + /** Constructor that takes array of certs. */ + public SdsTrustManagerFactory( + X509Certificate[] certs, @Nullable CertificateValidationContext certContext) + throws CertStoreException { + checkNotNull(certs, "certs"); + createSdsX509TrustManager(certs, certContext); + } + + private void createSdsX509TrustManager( + X509Certificate[] certs, CertificateValidationContext certContext) throws CertStoreException { + TrustManagerFactory tmf = null; + try { + tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + KeyStore ks = KeyStore.getInstance("PKCS12"); + // perform a load to initialize KeyStore + ks.load(/* stream= */ null, /* password= */ null); + int i = 1; + for (X509Certificate cert : certs) { + // note: alias lookup uses toLowerCase(Locale.ENGLISH) + // so our alias needs to be all lower-case and unique + ks.setCertificateEntry("alias" + Integer.toString(i), cert); + i++; + } + tmf.init(ks); + } catch (NoSuchAlgorithmException | KeyStoreException | IOException | CertificateException e) { + logger.log(Level.SEVERE, "createSdsX509TrustManager", e); + throw new CertStoreException(e); + } + TrustManager[] tms = tmf.getTrustManagers(); + X509ExtendedTrustManager myDelegate = null; + if (tms != null) { + for (TrustManager tm : tms) { + if (tm instanceof X509ExtendedTrustManager) { + myDelegate = (X509ExtendedTrustManager) tm; + break; + } + } + } + if (myDelegate == null) { + throw new CertStoreException("Native X509 TrustManager not found."); + } + sdsX509TrustManager = new SdsX509TrustManager(certContext, myDelegate); + } + + @Override + protected void engineInit(KeyStore keyStore) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + protected void engineInit(ManagerFactoryParameters managerFactoryParameters) throws Exception { + throw new UnsupportedOperationException(); + } + + @Override + protected TrustManager[] engineGetTrustManagers() { + return new TrustManager[] {sdsX509TrustManager}; + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java b/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java new file mode 100644 index 00000000000..e6eabcbb553 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java @@ -0,0 +1,132 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds.trust; + +import static com.google.common.truth.Truth.assertThat; + +import io.grpc.internal.testing.TestUtils; +import java.io.IOException; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import javax.net.ssl.TrustManager; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link SdsTrustManagerFactory}. */ +@RunWith(JUnit4.class) +public class SdsTrustManagerFactoryTest { + + /** Trust store cert. */ + private static final String CA_PEM_FILE = "ca.pem"; + + /** server cert. */ + private static final String SERVER_1_PEM_FILE = "server1.pem"; + + /** client cert. */ + private static final String CLIENT_PEM_FILE = "client.pem"; + + /** bad server cert. */ + private static final String BAD_SERVER_PEM_FILE = "badserver.pem"; + + /** bad client cert. */ + private static final String BAD_CLIENT_PEM_FILE = "badclient.pem"; + + @Test + public void constructor_fromFile() throws CertificateException, IOException, CertStoreException { + SdsTrustManagerFactory factory = + new SdsTrustManagerFactory( + TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + assertThat(factory).isNotNull(); + TrustManager[] tms = factory.getTrustManagers(); + assertThat(tms).isNotNull(); + assertThat(tms).hasLength(1); + TrustManager myTm = tms[0]; + assertThat(myTm).isInstanceOf(SdsX509TrustManager.class); + SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) myTm; + X509Certificate[] acceptedIssuers = sdsX509TrustManager.getAcceptedIssuers(); + assertThat(acceptedIssuers).isNotNull(); + assertThat(acceptedIssuers).hasLength(1); + X509Certificate caCert = acceptedIssuers[0]; + assertThat(caCert) + .isEqualTo(CertificateUtils.toX509Certificates(TestUtils.loadCert(CA_PEM_FILE))[0]); + } + + @Test + public void checkServerTrusted_goodCert() + throws CertificateException, IOException, CertStoreException { + SdsTrustManagerFactory factory = + new SdsTrustManagerFactory( + TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; + X509Certificate[] serverChain = + CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); + sdsX509TrustManager.checkServerTrusted(serverChain, "RSA"); + } + + @Test + public void checkClientTrusted_goodCert() + throws CertificateException, IOException, CertStoreException { + SdsTrustManagerFactory factory = + new SdsTrustManagerFactory( + TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; + X509Certificate[] clientChain = + CertificateUtils.toX509Certificates(TestUtils.loadCert(CLIENT_PEM_FILE)); + sdsX509TrustManager.checkClientTrusted(clientChain, "RSA"); + } + + @Test + public void checkServerTrusted_badCert_throwsException() + throws CertificateException, IOException, CertStoreException { + SdsTrustManagerFactory factory = + new SdsTrustManagerFactory( + TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; + X509Certificate[] serverChain = + CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_SERVER_PEM_FILE)); + try { + sdsX509TrustManager.checkServerTrusted(serverChain, "RSA"); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected) + .hasMessageThat() + .contains("unable to find valid certification path to requested target"); + } + } + + @Test + public void checkClientTrusted_badCert_throwsException() + throws CertificateException, IOException, CertStoreException { + SdsTrustManagerFactory factory = + new SdsTrustManagerFactory( + TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; + X509Certificate[] clientChain = + CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_CLIENT_PEM_FILE)); + try { + sdsX509TrustManager.checkClientTrusted(clientChain, "RSA"); + Assert.fail("no exception thrown"); + } catch (CertificateException expected) { + assertThat(expected) + .hasMessageThat() + .contains("unable to find valid certification path to requested target"); + } + } +} From 8d1ee9cfc70455cf0ac38ae13d15c7416a2c0c62 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Wed, 16 Oct 2019 15:15:28 -0700 Subject: [PATCH 101/131] xds: implementation of SslContextSecretVolumeSecretProvider (#6251) --- xds/build.gradle | 1 + .../java/io/grpc/xds/sds/SecretProvider.java | 8 +- .../SslContextSecretVolumeSecretProvider.java | 191 +++++++ ...ContextSecretVolumeSecretProviderTest.java | 523 ++++++++++++++++++ .../TlsCertificateSecretProviderMapTest.java | 15 +- ...ificateSecretVolumeSecretProviderTest.java | 10 + 6 files changed, 733 insertions(+), 15 deletions(-) create mode 100644 xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java create mode 100644 xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java diff --git a/xds/build.gradle b/xds/build.gradle index d69fdc9da6b..322529b8ef1 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -42,6 +42,7 @@ dependencies { project(':grpc-testing-proto'), libraries.guava_testlib signature "org.codehaus.mojo.signature:java17:1.0@signature" + testRuntime libraries.netty_tcnative } sourceSets { diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java index a3418521d6b..f7f5dd90941 100644 --- a/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java +++ b/xds/src/main/java/io/grpc/xds/sds/SecretProvider.java @@ -29,12 +29,16 @@ public interface SecretProvider { interface Callback { + /** Informs callee of new/updated secret. */ void updateSecret(T secret); + + /** Informs callee of an exception that was generated. */ + void onException(Throwable throwable); } /** - * Registers a callback on the given executor. The callback will run when secret becomes - * available or immediately if the result is already available. + * Registers a callback on the given executor. The callback will run when secret becomes available + * or immediately if the result is already available. */ void addCallback(Callback callback, Executor executor); } diff --git a/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java new file mode 100644 index 00000000000..5a7dc2e2447 --- /dev/null +++ b/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java @@ -0,0 +1,191 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.core.DataSource.SpecifierCase; +import io.grpc.netty.GrpcSslContexts; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import java.io.File; +import java.util.concurrent.Executor; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.Nullable; +import javax.net.ssl.SSLException; + +/** + * An SslContext provider that uses file-based secrets (secret volume). Used for both server and + * client SslContexts + */ +final class SslContextSecretVolumeSecretProvider implements SecretProvider { + + private static final Logger logger = + Logger.getLogger(SslContextSecretVolumeSecretProvider.class.getName()); + + private final boolean server; + @Nullable private final String privateKey; + @Nullable private final String privateKeyPassword; + @Nullable private final String certificateChain; + @Nullable private final String trustedCa; + + private SslContextSecretVolumeSecretProvider( + @Nullable String privateKey, + @Nullable String privateKeyPassword, + @Nullable String certificateChain, + @Nullable String trustedCa, + boolean server) { + this.privateKey = privateKey; + this.privateKeyPassword = privateKeyPassword; + this.certificateChain = certificateChain; + this.trustedCa = trustedCa; + this.server = server; + } + + @VisibleForTesting + @Nullable + static CertificateValidationContext validateCertificateContext( + @Nullable CertificateValidationContext certContext, boolean optional) { + if (certContext == null || !certContext.hasTrustedCa()) { + checkArgument(optional, "certContext is required"); + return null; + } + checkArgument( + certContext.getTrustedCa().getSpecifierCase() == SpecifierCase.FILENAME, + "filename expected"); + return certContext; + } + + @VisibleForTesting + @Nullable + static TlsCertificate validateTlsCertificate( + @Nullable TlsCertificate tlsCertificate, boolean optional) { + if (tlsCertificate == null) { + checkArgument(optional, "tlsCertificate is required"); + return null; + } + if (optional + && (tlsCertificate.getPrivateKey().getSpecifierCase() == SpecifierCase.SPECIFIER_NOT_SET) + && (tlsCertificate.getCertificateChain().getSpecifierCase() + == SpecifierCase.SPECIFIER_NOT_SET)) { + return null; + } + checkArgument( + tlsCertificate.getPrivateKey().getSpecifierCase() == SpecifierCase.FILENAME, + "filename expected"); + checkArgument( + tlsCertificate.getCertificateChain().getSpecifierCase() == SpecifierCase.FILENAME, + "filename expected"); + return tlsCertificate; + } + + static SslContextSecretVolumeSecretProvider getProviderForServer( + TlsCertificate tlsCertificate, @Nullable CertificateValidationContext certContext) { + // first validate + validateTlsCertificate(tlsCertificate, /* optional= */ false); + // certContext exists in case of mTLS, else null for a server + if (certContext != null) { + certContext = validateCertificateContext(certContext, /* optional= */ true); + } + String privateKeyPassword = + tlsCertificate.hasPassword() ? tlsCertificate.getPassword().getInlineString() : null; + String trustedCa = certContext != null ? certContext.getTrustedCa().getFilename() : null; + return new SslContextSecretVolumeSecretProvider( + tlsCertificate.getPrivateKey().getFilename(), + privateKeyPassword, + tlsCertificate.getCertificateChain().getFilename(), + trustedCa, + /* server= */ true); + } + + static SslContextSecretVolumeSecretProvider getProviderForClient( + @Nullable TlsCertificate tlsCertificate, CertificateValidationContext certContext) { + // first validate + validateCertificateContext(certContext, /* optional= */ false); + // tlsCertificate exists in case of mTLS, else null for a client + if (tlsCertificate != null) { + tlsCertificate = validateTlsCertificate(tlsCertificate, /* optional= */ true); + } + String privateKey = null; + String privateKeyPassword = null; + String certificateChain = null; + if (tlsCertificate != null) { + privateKey = tlsCertificate.getPrivateKey().getFilename(); + if (tlsCertificate.hasPassword()) { + privateKeyPassword = tlsCertificate.getPassword().getInlineString(); + } + certificateChain = tlsCertificate.getCertificateChain().getFilename(); + } + return new SslContextSecretVolumeSecretProvider( + privateKey, + privateKeyPassword, + certificateChain, + certContext.getTrustedCa().getFilename(), + /* server= */ false); + } + + @Override + public void addCallback(final Callback callback, Executor executor) { + checkNotNull(callback, "callback"); + checkNotNull(executor, "executor"); + executor.execute( + new Runnable() { + @Override + public void run() { + // as per the contract we will read the current secrets on disk + // this involves I/O which can potentially block the executor or event loop + SslContext sslContext = null; + try { + sslContext = buildSslContextFromSecrets(); + try { + callback.updateSecret(sslContext); + } catch (Throwable t) { + logger.log(Level.SEVERE, "Exception from callback.updateSecret", t); + } + } catch (Throwable e) { + logger.log(Level.SEVERE, "Exception from buildSslContextFromSecrets", e); + callback.onException(e); + } + } + }); + } + + @VisibleForTesting + SslContext buildSslContextFromSecrets() throws SSLException { + SslContextBuilder sslContextBuilder; + if (server) { + sslContextBuilder = + GrpcSslContexts.forServer( + new File(certificateChain), new File(privateKey), privateKeyPassword); + if (trustedCa != null) { + sslContextBuilder.trustManager(new File(trustedCa)); + } + } else { + sslContextBuilder = GrpcSslContexts.forClient().trustManager(new File(trustedCa)); + if (privateKey != null && certificateChain != null) { + sslContextBuilder.keyManager( + new File(certificateChain), new File(privateKey), privateKeyPassword); + } + } + return sslContextBuilder.build(); + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java b/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java new file mode 100644 index 00000000000..fe7b8129607 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java @@ -0,0 +1,523 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.util.concurrent.MoreExecutors; +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.core.DataSource; +import io.grpc.internal.testing.TestUtils; +import io.netty.handler.ssl.SslContext; +import java.io.IOException; +import java.util.List; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link SslContextSecretVolumeSecretProvider}. */ +@RunWith(JUnit4.class) +public class SslContextSecretVolumeSecretProviderTest { + + private static final String SERVER_1_PEM_FILE = "server1.pem"; + private static final String SERVER_1_KEY_FILE = "server1.key"; + private static final String CLIENT_PEM_FILE = "client.pem"; + private static final String CLIENT_KEY_FILE = "client.key"; + private static final String CA_PEM_FILE = "ca.pem"; + + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void validateCertificateContext_nullAndNotOptional_throwsException() { + // expect exception when certContext is null and not optional + try { + SslContextSecretVolumeSecretProvider.validateCertificateContext( + /* certContext= */ null, /* optional= */ false); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("certContext is required"); + } + } + + @Test + public void validateCertificateContext_missingTrustCa_throwsException() { + // expect exception when certContext has no CA and not optional + CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); + try { + SslContextSecretVolumeSecretProvider.validateCertificateContext( + certContext, /* optional= */ false); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("certContext is required"); + } + } + + @Test + public void validateCertificateContext_nullAndOptional() { + // certContext argument can be null when optional + CertificateValidationContext certContext = + SslContextSecretVolumeSecretProvider.validateCertificateContext( + /* certContext= */ null, /* optional= */ true); + assertThat(certContext).isNull(); + } + + @Test + public void validateCertificateContext_missingTrustCaOptional() { + // certContext argument can have missing CA when optional + CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); + assertThat( + SslContextSecretVolumeSecretProvider.validateCertificateContext( + certContext, /* optional= */ true)) + .isNull(); + } + + @Test + public void validateCertificateContext_inlineString_throwsException() { + // expect exception when certContext doesn't use filename (inline string) + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setInlineString("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateCertificateContext( + certContext, /* optional= */ false); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void validateCertificateContext_filename() { + // validation succeeds and returns same instance when filename provided + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setFilename("bar")) + .build(); + assertThat( + SslContextSecretVolumeSecretProvider.validateCertificateContext( + certContext, /* optional= */ false)) + .isSameInstanceAs(certContext); + } + + @Test + public void validateTlsCertificate_nullAndNotOptional_throwsException() { + // expect exception when tlsCertificate is null and not optional + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate( + /* tlsCertificate= */ null, /* optional= */ false); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("tlsCertificate is required"); + } + } + + @Test + public void validateTlsCertificate_nullOptional() { + assertThat( + SslContextSecretVolumeSecretProvider.validateTlsCertificate( + /* tlsCertificate= */ null, /* optional= */ true)) + .isNull(); + } + + @Test + public void validateTlsCertificate_defaultInstance_returnsNull() { + // tlsCertificate is not null but has no value (default instance): expect null + TlsCertificate tlsCert = TlsCertificate.getDefaultInstance(); + assertThat( + SslContextSecretVolumeSecretProvider.validateTlsCertificate( + tlsCert, /* optional= */ true)) + .isNull(); + } + + @Test + public void validateTlsCertificate_missingCertChainNotOptional_throwsException() { + // expect exception when tlsCertificate has missing certChain and not optional + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setPrivateKey(DataSource.newBuilder().setInlineString("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ false); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void validateTlsCertificate_missingCertChainOptional_throwsException() { + // expect exception when tlsCertificate has missing certChain even if optional + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setPrivateKey(DataSource.newBuilder().setInlineString("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void validateTlsCertificate_missingPrivateKeyNotOptional_throwsException() { + // expect exception when tlsCertificate has missing private key and not optional + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setInlineString("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ false); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void validateTlsCertificate_missingPrivateKeyOptional_throwsException() { + // expect exception when tlsCertificate has missing private key even if optional + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setInlineString("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void validateTlsCertificate_optional_returnsSameInstance() { + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setFilename("foo")) + .setPrivateKey(DataSource.newBuilder().setFilename("bar")) + .build(); + assertThat( + SslContextSecretVolumeSecretProvider.validateTlsCertificate( + tlsCert, /* optional= */ true)) + .isSameInstanceAs(tlsCert); + } + + @Test + public void validateTlsCertificate_notOptional_returnsSameInstance() { + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setFilename("foo")) + .setPrivateKey(DataSource.newBuilder().setFilename("bar")) + .build(); + assertThat( + SslContextSecretVolumeSecretProvider.validateTlsCertificate( + tlsCert, /* optional= */ false)) + .isSameInstanceAs(tlsCert); + } + + @Test + public void validateTlsCertificate_certChainInlineString_throwsException() { + // expect exception when tlsCertificate has certChain as inline string + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setInlineString("foo")) + .setPrivateKey(DataSource.newBuilder().setFilename("bar")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void validateTlsCertificate_privateKeyInlineString_throwsException() { + // expect exception when tlsCertificate has private key as inline string + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setPrivateKey(DataSource.newBuilder().setInlineString("foo")) + .setCertificateChain(DataSource.newBuilder().setFilename("bar")) + .build(); + try { + SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void getProviderForServer_nullTlsCertificate_throwsException() { + try { + SslContextSecretVolumeSecretProvider.getProviderForServer( + /* tlsCertificate= */ null, /* certContext= */ null); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("tlsCertificate is required"); + } + } + + @Test + public void getProviderForServer_defaultTlsCertificate_throwsException() { + TlsCertificate tlsCert = TlsCertificate.getDefaultInstance(); + try { + SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, /* certContext= */ null); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void getProviderForServer_certContextWithInlineString_throwsException() { + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setFilename("foo")) + .setPrivateKey(DataSource.newBuilder().setFilename("bar")) + .build(); + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setInlineString("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, certContext); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void getProviderForClient_nullCertContext_throwsException() { + try { + SslContextSecretVolumeSecretProvider.getProviderForClient( + /* tlsCertificate= */ null, /* certContext= */ null); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("certContext is required"); + } + } + + @Test + public void getProviderForClient_defaultCertContext_throwsException() { + CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); + try { + SslContextSecretVolumeSecretProvider.getProviderForClient( + /* tlsCertificate= */ null, certContext); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("certContext is required"); + } + } + + @Test + public void getProviderForClient_certWithPrivateKeyInlineString_throwsException() { + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setFilename("foo")) + .setPrivateKey(DataSource.newBuilder().setInlineString("bar")) + .build(); + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setFilename("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + @Test + public void getProviderForClient_certWithCertChainInlineString_throwsException() { + TlsCertificate tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setInlineString("foo")) + .setPrivateKey(DataSource.newBuilder().setFilename("bar")) + .build(); + CertificateValidationContext certContext = + CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setFilename("foo")) + .build(); + try { + SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).isEqualTo("filename expected"); + } + } + + private static String getTempFileNameForResourcesFile(String resFile) throws IOException { + return TestUtils.loadCert(resFile).getAbsolutePath(); + } + + /** Helper method to build SslContextSecretVolumeSecretProvider from given files. */ + private static SslContextSecretVolumeSecretProvider getSslContextSecretVolumeSecretProvider( + boolean server, String certChainFilename, String privateKeyFilename, String trustedCaFilename) + throws IOException { + + // get temp file for each file + if (certChainFilename != null) { + certChainFilename = getTempFileNameForResourcesFile(certChainFilename); + } + if (privateKeyFilename != null) { + privateKeyFilename = getTempFileNameForResourcesFile(privateKeyFilename); + } + if (trustedCaFilename != null) { + trustedCaFilename = getTempFileNameForResourcesFile(trustedCaFilename); + } + + TlsCertificate tlsCert = + (certChainFilename == null && privateKeyFilename == null) + ? null + : TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setFilename(certChainFilename)) + .setPrivateKey(DataSource.newBuilder().setFilename(privateKeyFilename)) + .build(); + CertificateValidationContext certContext = + trustedCaFilename == null + ? null + : CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setFilename(trustedCaFilename)) + .build(); + + return server + ? SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, certContext) + : SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); + } + + /** + * Helper method to build SslContextSecretVolumeSecretProvider, call buildSslContext on it and + * check returned SslContext. + */ + private void sslContextForEitherWithBothCertAndTrust( + boolean server, String pemFile, String keyFile, String caFile) throws IOException { + SslContextSecretVolumeSecretProvider provider = + getSslContextSecretVolumeSecretProvider(server, pemFile, keyFile, caFile); + + SslContext sslContext = provider.buildSslContextFromSecrets(); + doChecksOnSslContext(server, sslContext); + } + + private void doChecksOnSslContext(boolean server, SslContext sslContext) { + if (server) { + assertThat(sslContext.isServer()).isTrue(); + } else { + assertThat(sslContext.isClient()).isTrue(); + } + List apnProtos = sslContext.applicationProtocolNegotiator().protocols(); + assertThat(apnProtos).isNotNull(); + assertThat(apnProtos).contains("h2"); + } + + @Test + public void getProviderForServer() throws IOException { + sslContextForEitherWithBothCertAndTrust( + true, SERVER_1_PEM_FILE, SERVER_1_KEY_FILE, CA_PEM_FILE); + } + + @Test + public void getProviderForClient() throws IOException { + sslContextForEitherWithBothCertAndTrust(false, CLIENT_PEM_FILE, CLIENT_KEY_FILE, CA_PEM_FILE); + } + + @Test + public void getProviderForServer_onlyCert() throws IOException { + sslContextForEitherWithBothCertAndTrust(true, SERVER_1_PEM_FILE, SERVER_1_KEY_FILE, null); + } + + @Test + public void getProviderForClient_onlyTrust() throws IOException { + sslContextForEitherWithBothCertAndTrust(false, null, null, CA_PEM_FILE); + } + + @Test + public void getProviderForServer_badFile_throwsException() throws IOException { + try { + sslContextForEitherWithBothCertAndTrust(true, SERVER_1_PEM_FILE, SERVER_1_PEM_FILE, null); + Assert.fail("no exception thrown"); + } catch (IllegalArgumentException expected) { + assertThat(expected.getMessage()).contains("File does not contain valid private key"); + } + } + + static class TestCallback implements SecretProvider.Callback { + + T updatedSecret; + Throwable updatedThrowable; + + @Override + public void updateSecret(T secret) { + updatedSecret = secret; + } + + @Override + public void onException(Throwable throwable) { + updatedThrowable = throwable; + } + } + + /** + * Helper method to get the value thru directExecutor callback. Because of directExecutor this is + * a synchronous callback - so need to provide a listener. + */ + private static TestCallback getValueThruCallback( + SecretProvider provider) { + TestCallback testCallback = new TestCallback<>(); + provider.addCallback(testCallback, MoreExecutors.directExecutor()); + return testCallback; + } + + @Test + public void getProviderForServer_both_callsback() throws IOException { + SslContextSecretVolumeSecretProvider provider = + getSslContextSecretVolumeSecretProvider( + true, SERVER_1_PEM_FILE, SERVER_1_KEY_FILE, CA_PEM_FILE); + + TestCallback testCallback = getValueThruCallback(provider); + doChecksOnSslContext(true, testCallback.updatedSecret); + } + + @Test + public void getProviderForClient_both_callsback() throws IOException { + SslContextSecretVolumeSecretProvider provider = + getSslContextSecretVolumeSecretProvider( + false, CLIENT_PEM_FILE, CLIENT_KEY_FILE, CA_PEM_FILE); + + TestCallback testCallback = getValueThruCallback(provider); + doChecksOnSslContext(false, testCallback.updatedSecret); + } + + @Test + public void getProviderForClient_both_callsback_setException() throws IOException { + SslContextSecretVolumeSecretProvider provider = + getSslContextSecretVolumeSecretProvider( + false, CLIENT_PEM_FILE, CLIENT_PEM_FILE, CA_PEM_FILE); + TestCallback testCallback = getValueThruCallback(provider); + assertThat(testCallback.updatedSecret).isNull(); + assertThat(testCallback.updatedThrowable).isInstanceOf(IllegalArgumentException.class); + assertThat(testCallback.updatedThrowable.getMessage()) + .contains("File does not contain valid private key"); + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java index 681cab46d81..297b1b022bd 100644 --- a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java @@ -58,27 +58,16 @@ static ConfigSource createFileAndConfigSource(TemporaryFolder temporaryFolder) .build(); } - static class TestCallback implements - SecretProvider.Callback { - - TlsCertificateStore updatedSecret; - - @Override - public void updateSecret(TlsCertificateStore secret) { - updatedSecret = secret; - } - } - /** * Helper method to get the value thru directExecutore callback. Used by other classes. */ static TlsCertificateStore getValueThruCallback(SecretProvider provider) { - TestCallback testCallback = new TestCallback(); + SslContextSecretVolumeSecretProviderTest.TestCallback testCallback + = new SslContextSecretVolumeSecretProviderTest.TestCallback<>(); provider.addCallback(testCallback, MoreExecutors.directExecutor()); return testCallback.updatedSecret; } - @Test public void createTest() throws IOException, ExecutionException, InterruptedException { ConfigSource configSource = createFileAndConfigSource(temporaryFolder); diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java index 92b33f877a7..cc202f4a5b9 100644 --- a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java @@ -95,6 +95,11 @@ public void verifyCallbackExecuted() public void updateSecret(TlsCertificateStore secret) { listenerRun = true; } + + @Override + public void onException(Throwable throwable) { + + } }, MoreExecutors.directExecutor()); assertThat(listenerRun).isTrue(); } @@ -131,6 +136,11 @@ public void verifyCallbackNotExecuted() public void updateSecret(TlsCertificateStore secret) { listenerRun = true; } + + @Override + public void onException(Throwable throwable) { + + } }, MoreExecutors.directExecutor()); assertThat(listenerRun).isFalse(); } From 9a34ceece681ef1b86e39ee45943da247f8e18b6 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Wed, 16 Oct 2019 16:50:03 -0700 Subject: [PATCH 102/131] xds: fix lint warnings (#6289) --- .../xds/sds/trust/SdsTrustManagerFactory.java | 2 +- ...ContextSecretVolumeSecretProviderTest.java | 40 +++++++++---------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java b/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java index 0b19721beb1..2e6edc6b370 100644 --- a/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java +++ b/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java @@ -74,7 +74,7 @@ private void createSdsX509TrustManager( for (X509Certificate cert : certs) { // note: alias lookup uses toLowerCase(Locale.ENGLISH) // so our alias needs to be all lower-case and unique - ks.setCertificateEntry("alias" + Integer.toString(i), cert); + ks.setCertificateEntry("alias" + i, cert); i++; } tmf.init(ks); diff --git a/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java b/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java index fe7b8129607..1510cc6fcd9 100644 --- a/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java @@ -53,7 +53,7 @@ public void validateCertificateContext_nullAndNotOptional_throwsException() { /* certContext= */ null, /* optional= */ false); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("certContext is required"); + assertThat(expected).hasMessageThat().isEqualTo("certContext is required"); } } @@ -66,7 +66,7 @@ public void validateCertificateContext_missingTrustCa_throwsException() { certContext, /* optional= */ false); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("certContext is required"); + assertThat(expected).hasMessageThat().isEqualTo("certContext is required"); } } @@ -101,7 +101,7 @@ public void validateCertificateContext_inlineString_throwsException() { certContext, /* optional= */ false); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -126,7 +126,7 @@ public void validateTlsCertificate_nullAndNotOptional_throwsException() { /* tlsCertificate= */ null, /* optional= */ false); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("tlsCertificate is required"); + assertThat(expected).hasMessageThat().isEqualTo("tlsCertificate is required"); } } @@ -159,7 +159,7 @@ public void validateTlsCertificate_missingCertChainNotOptional_throwsException() SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ false); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -174,7 +174,7 @@ public void validateTlsCertificate_missingCertChainOptional_throwsException() { SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -189,7 +189,7 @@ public void validateTlsCertificate_missingPrivateKeyNotOptional_throwsException( SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ false); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -204,7 +204,7 @@ public void validateTlsCertificate_missingPrivateKeyOptional_throwsException() { SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -246,7 +246,7 @@ public void validateTlsCertificate_certChainInlineString_throwsException() { SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -262,7 +262,7 @@ public void validateTlsCertificate_privateKeyInlineString_throwsException() { SslContextSecretVolumeSecretProvider.validateTlsCertificate(tlsCert, /* optional= */ true); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -273,7 +273,7 @@ public void getProviderForServer_nullTlsCertificate_throwsException() { /* tlsCertificate= */ null, /* certContext= */ null); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("tlsCertificate is required"); + assertThat(expected).hasMessageThat().isEqualTo("tlsCertificate is required"); } } @@ -284,7 +284,7 @@ public void getProviderForServer_defaultTlsCertificate_throwsException() { SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, /* certContext= */ null); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -314,7 +314,7 @@ public void getProviderForClient_nullCertContext_throwsException() { /* tlsCertificate= */ null, /* certContext= */ null); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("certContext is required"); + assertThat(expected).hasMessageThat().isEqualTo("certContext is required"); } } @@ -326,7 +326,7 @@ public void getProviderForClient_defaultCertContext_throwsException() { /* tlsCertificate= */ null, certContext); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("certContext is required"); + assertThat(expected).hasMessageThat().isEqualTo("certContext is required"); } } @@ -345,7 +345,7 @@ public void getProviderForClient_certWithPrivateKeyInlineString_throwsException( SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -364,7 +364,7 @@ public void getProviderForClient_certWithCertChainInlineString_throwsException() SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).isEqualTo("filename expected"); + assertThat(expected).hasMessageThat().isEqualTo("filename expected"); } } @@ -411,7 +411,7 @@ private static SslContextSecretVolumeSecretProvider getSslContextSecretVolumeSec * Helper method to build SslContextSecretVolumeSecretProvider, call buildSslContext on it and * check returned SslContext. */ - private void sslContextForEitherWithBothCertAndTrust( + private static void sslContextForEitherWithBothCertAndTrust( boolean server, String pemFile, String keyFile, String caFile) throws IOException { SslContextSecretVolumeSecretProvider provider = getSslContextSecretVolumeSecretProvider(server, pemFile, keyFile, caFile); @@ -420,7 +420,7 @@ private void sslContextForEitherWithBothCertAndTrust( doChecksOnSslContext(server, sslContext); } - private void doChecksOnSslContext(boolean server, SslContext sslContext) { + private static void doChecksOnSslContext(boolean server, SslContext sslContext) { if (server) { assertThat(sslContext.isServer()).isTrue(); } else { @@ -458,7 +458,7 @@ public void getProviderForServer_badFile_throwsException() throws IOException { sslContextForEitherWithBothCertAndTrust(true, SERVER_1_PEM_FILE, SERVER_1_PEM_FILE, null); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { - assertThat(expected.getMessage()).contains("File does not contain valid private key"); + assertThat(expected).hasMessageThat().contains("File does not contain valid private key"); } } @@ -517,7 +517,7 @@ public void getProviderForClient_both_callsback_setException() throws IOExceptio TestCallback testCallback = getValueThruCallback(provider); assertThat(testCallback.updatedSecret).isNull(); assertThat(testCallback.updatedThrowable).isInstanceOf(IllegalArgumentException.class); - assertThat(testCallback.updatedThrowable.getMessage()) + assertThat(testCallback.updatedThrowable).hasMessageThat() .contains("File does not contain valid private key"); } } From 40f401d0e70bd7b0ea16f6cc155a83dad19b6b25 Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Thu, 17 Oct 2019 07:39:18 -0700 Subject: [PATCH 103/131] api: Clarify setting safe/idempotent may change other value --- api/src/main/java/io/grpc/MethodDescriptor.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/io/grpc/MethodDescriptor.java b/api/src/main/java/io/grpc/MethodDescriptor.java index 105db29e561..6e3c42918db 100644 --- a/api/src/main/java/io/grpc/MethodDescriptor.java +++ b/api/src/main/java/io/grpc/MethodDescriptor.java @@ -534,7 +534,9 @@ public Builder setSchemaDescriptor(@Nullable Object schemaDescripto /** * Sets whether the method is idempotent. If true, calling this method more than once doesn't - * have additional side effects. If {@code false}, method is also not safe. + * have additional side effects. If {@code false}, method is also not safe. Note that implies + * calling {@code builder.setIdempotent(false).setIdempotent(true)} will leave {@code + * isSafe() == false}. * * @since 1.1.0 */ @@ -549,7 +551,8 @@ public Builder setIdempotent(boolean idempotent) { /** * Sets whether this method is safe. If true, calling this method any number of times doesn't - * have side effects. If {@code true}, method is also idempotent. + * have side effects. If {@code true}, method is also idempotent. Note that implies calling + * {@code builder.setSafe(true).setSafe(false)} will leave {@code isIdempotent() == true}. * * @since 1.1.0 */ From 45d49a56cc32ee2b133b83c3743f719dc8df306b Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 17 Oct 2019 14:49:24 -0700 Subject: [PATCH 104/131] stub,compiler: generated stub extends Abstract{Async,Future,Blocking}Stub (#6196) --- .../alts/internal/HandshakerServiceGrpc.java | 69 +++++++------ .../proto/BenchmarkServiceGrpc.java | 69 +++++++------ .../proto/ReportQpsScenarioServiceGrpc.java | 69 +++++++------ .../benchmarks/proto/WorkerServiceGrpc.java | 69 +++++++------ .../src/java_plugin/cpp/java_generator.cpp | 76 +++++++++++---- .../golden/TestDeprecatedService.java.txt | 69 +++++++------ compiler/src/test/golden/TestService.java.txt | 69 +++++++------ .../golden/TestDeprecatedService.java.txt | 69 +++++++------ .../src/testLite/golden/TestService.java.txt | 69 +++++++------ .../grpc/io/grpc/lb/v1/LoadBalancerGrpc.java | 69 +++++++------ .../integration/MetricsServiceGrpc.java | 69 +++++++------ .../integration/ReconnectServiceGrpc.java | 69 +++++++------ .../testing/integration/TestServiceGrpc.java | 69 +++++++------ .../integration/UnimplementedServiceGrpc.java | 69 +++++++------ .../io/grpc/channelz/v1/ChannelzGrpc.java | 69 +++++++------ .../grpc/io/grpc/health/v1/HealthGrpc.java | 69 +++++++------ .../v1alpha/ServerReflectionGrpc.java | 69 +++++++------ .../testing/AnotherDynamicServiceGrpc.java | 69 +++++++------ .../testing/DynamicServiceGrpc.java | 69 +++++++------ .../testing/ReflectableServiceGrpc.java | 69 +++++++------ .../java/io/grpc/stub/AbstractAsyncStub.java | 69 +++++++++++++ .../io/grpc/stub/AbstractBlockingStub.java | 70 +++++++++++++ .../java/io/grpc/stub/AbstractFutureStub.java | 70 +++++++++++++ .../main/java/io/grpc/stub/AbstractStub.java | 34 +++++++ .../main/java/io/grpc/stub/ClientCalls.java | 10 ++ .../io/grpc/stub/InternalClientCalls.java | 61 ++++++++++++ .../io/grpc/stub/AbstractAsyncStubTest.java | 94 ++++++++++++++++++ .../grpc/stub/AbstractBlockingStubTest.java | 97 +++++++++++++++++++ .../io/grpc/stub/AbstractFutureStubTest.java | 94 ++++++++++++++++++ .../java/io/grpc/stub/AbstractStubTest.java | 79 ++++----------- .../io/grpc/stub/BaseAbstractStubTest.java | 86 ++++++++++++++++ .../testing/protobuf/SimpleServiceGrpc.java | 69 +++++++------ .../service/orca/v1/OpenRcaServiceGrpc.java | 69 +++++++------ .../api/v2/EndpointDiscoveryServiceGrpc.java | 69 +++++++------ .../v2/AggregatedDiscoveryServiceGrpc.java | 69 +++++++------ .../v2/LoadReportingServiceGrpc.java | 69 +++++++------ 36 files changed, 1699 insertions(+), 797 deletions(-) create mode 100644 stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java create mode 100644 stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java create mode 100644 stub/src/main/java/io/grpc/stub/AbstractFutureStub.java create mode 100644 stub/src/main/java/io/grpc/stub/InternalClientCalls.java create mode 100644 stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java create mode 100644 stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java create mode 100644 stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java create mode 100644 stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java diff --git a/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java b/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java index a792853a45a..9f68246d9e0 100644 --- a/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java +++ b/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java @@ -62,7 +62,14 @@ io.grpc.alts.internal.HandshakerResp> getDoHandshakeMethod() { * Creates a new async stub that supports all call types for the service */ public static HandshakerServiceStub newStub(io.grpc.Channel channel) { - return new HandshakerServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public HandshakerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HandshakerServiceStub(channel, callOptions); + } + }; + return HandshakerServiceStub.newStub(factory, channel); } /** @@ -70,7 +77,14 @@ public static HandshakerServiceStub newStub(io.grpc.Channel channel) { */ public static HandshakerServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new HandshakerServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public HandshakerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HandshakerServiceBlockingStub(channel, callOptions); + } + }; + return HandshakerServiceBlockingStub.newStub(factory, channel); } /** @@ -78,7 +92,14 @@ public static HandshakerServiceBlockingStub newBlockingStub( */ public static HandshakerServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new HandshakerServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public HandshakerServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HandshakerServiceFutureStub(channel, callOptions); + } + }; + return HandshakerServiceFutureStub.newStub(factory, channel); } /** @@ -115,19 +136,15 @@ public io.grpc.stub.StreamObserver doHandsh /** */ - public static final class HandshakerServiceStub extends io.grpc.stub.AbstractStub { - private HandshakerServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private HandshakerServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class HandshakerServiceStub extends io.grpc.stub.AbstractAsyncStub { + private HandshakerServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HandshakerServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected HandshakerServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new HandshakerServiceStub(channel, callOptions); } @@ -150,38 +167,30 @@ public io.grpc.stub.StreamObserver doHandsh /** */ - public static final class HandshakerServiceBlockingStub extends io.grpc.stub.AbstractStub { - private HandshakerServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private HandshakerServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class HandshakerServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private HandshakerServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HandshakerServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected HandshakerServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new HandshakerServiceBlockingStub(channel, callOptions); } } /** */ - public static final class HandshakerServiceFutureStub extends io.grpc.stub.AbstractStub { - private HandshakerServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private HandshakerServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class HandshakerServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private HandshakerServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HandshakerServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected HandshakerServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new HandshakerServiceFutureStub(channel, callOptions); } } diff --git a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java index c7614532168..0ddf244e412 100644 --- a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java +++ b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java @@ -186,7 +186,14 @@ io.grpc.benchmarks.proto.Messages.SimpleResponse> getStreamingBothWaysMethod() { * Creates a new async stub that supports all call types for the service */ public static BenchmarkServiceStub newStub(io.grpc.Channel channel) { - return new BenchmarkServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public BenchmarkServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new BenchmarkServiceStub(channel, callOptions); + } + }; + return BenchmarkServiceStub.newStub(factory, channel); } /** @@ -194,7 +201,14 @@ public static BenchmarkServiceStub newStub(io.grpc.Channel channel) { */ public static BenchmarkServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new BenchmarkServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public BenchmarkServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new BenchmarkServiceBlockingStub(channel, callOptions); + } + }; + return BenchmarkServiceBlockingStub.newStub(factory, channel); } /** @@ -202,7 +216,14 @@ public static BenchmarkServiceBlockingStub newBlockingStub( */ public static BenchmarkServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new BenchmarkServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public BenchmarkServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new BenchmarkServiceFutureStub(channel, callOptions); + } + }; + return BenchmarkServiceFutureStub.newStub(factory, channel); } /** @@ -308,19 +329,15 @@ public io.grpc.stub.StreamObserver { - private BenchmarkServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private BenchmarkServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class BenchmarkServiceStub extends io.grpc.stub.AbstractAsyncStub { + private BenchmarkServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected BenchmarkServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected BenchmarkServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new BenchmarkServiceStub(channel, callOptions); } @@ -388,19 +405,15 @@ public io.grpc.stub.StreamObserver { - private BenchmarkServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private BenchmarkServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class BenchmarkServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private BenchmarkServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected BenchmarkServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected BenchmarkServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new BenchmarkServiceBlockingStub(channel, callOptions); } @@ -430,19 +443,15 @@ public java.util.Iterator stre /** */ - public static final class BenchmarkServiceFutureStub extends io.grpc.stub.AbstractStub { - private BenchmarkServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private BenchmarkServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class BenchmarkServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private BenchmarkServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected BenchmarkServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected BenchmarkServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new BenchmarkServiceFutureStub(channel, callOptions); } diff --git a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java index 3bd2bdb96b0..8ccaf01fad9 100644 --- a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java +++ b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java @@ -62,7 +62,14 @@ io.grpc.benchmarks.proto.Control.Void> getReportScenarioMethod() { * Creates a new async stub that supports all call types for the service */ public static ReportQpsScenarioServiceStub newStub(io.grpc.Channel channel) { - return new ReportQpsScenarioServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReportQpsScenarioServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReportQpsScenarioServiceStub(channel, callOptions); + } + }; + return ReportQpsScenarioServiceStub.newStub(factory, channel); } /** @@ -70,7 +77,14 @@ public static ReportQpsScenarioServiceStub newStub(io.grpc.Channel channel) { */ public static ReportQpsScenarioServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new ReportQpsScenarioServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReportQpsScenarioServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReportQpsScenarioServiceBlockingStub(channel, callOptions); + } + }; + return ReportQpsScenarioServiceBlockingStub.newStub(factory, channel); } /** @@ -78,7 +92,14 @@ public static ReportQpsScenarioServiceBlockingStub newBlockingStub( */ public static ReportQpsScenarioServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new ReportQpsScenarioServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReportQpsScenarioServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReportQpsScenarioServiceFutureStub(channel, callOptions); + } + }; + return ReportQpsScenarioServiceFutureStub.newStub(factory, channel); } /** @@ -110,19 +131,15 @@ public void reportScenario(io.grpc.benchmarks.proto.Control.ScenarioResult reque /** */ - public static final class ReportQpsScenarioServiceStub extends io.grpc.stub.AbstractStub { - private ReportQpsScenarioServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private ReportQpsScenarioServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReportQpsScenarioServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ReportQpsScenarioServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReportQpsScenarioServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReportQpsScenarioServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReportQpsScenarioServiceStub(channel, callOptions); } @@ -140,19 +157,15 @@ public void reportScenario(io.grpc.benchmarks.proto.Control.ScenarioResult reque /** */ - public static final class ReportQpsScenarioServiceBlockingStub extends io.grpc.stub.AbstractStub { - private ReportQpsScenarioServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private ReportQpsScenarioServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReportQpsScenarioServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ReportQpsScenarioServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReportQpsScenarioServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReportQpsScenarioServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReportQpsScenarioServiceBlockingStub(channel, callOptions); } @@ -169,19 +182,15 @@ public io.grpc.benchmarks.proto.Control.Void reportScenario(io.grpc.benchmarks.p /** */ - public static final class ReportQpsScenarioServiceFutureStub extends io.grpc.stub.AbstractStub { - private ReportQpsScenarioServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private ReportQpsScenarioServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReportQpsScenarioServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ReportQpsScenarioServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReportQpsScenarioServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReportQpsScenarioServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReportQpsScenarioServiceFutureStub(channel, callOptions); } diff --git a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java index 05e85553c4b..9fc781c24b5 100644 --- a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java +++ b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java @@ -155,7 +155,14 @@ io.grpc.benchmarks.proto.Control.Void> getQuitWorkerMethod() { * Creates a new async stub that supports all call types for the service */ public static WorkerServiceStub newStub(io.grpc.Channel channel) { - return new WorkerServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public WorkerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkerServiceStub(channel, callOptions); + } + }; + return WorkerServiceStub.newStub(factory, channel); } /** @@ -163,7 +170,14 @@ public static WorkerServiceStub newStub(io.grpc.Channel channel) { */ public static WorkerServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new WorkerServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public WorkerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkerServiceBlockingStub(channel, callOptions); + } + }; + return WorkerServiceBlockingStub.newStub(factory, channel); } /** @@ -171,7 +185,14 @@ public static WorkerServiceBlockingStub newBlockingStub( */ public static WorkerServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new WorkerServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public WorkerServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new WorkerServiceFutureStub(channel, callOptions); + } + }; + return WorkerServiceFutureStub.newStub(factory, channel); } /** @@ -264,19 +285,15 @@ public void quitWorker(io.grpc.benchmarks.proto.Control.Void request, /** */ - public static final class WorkerServiceStub extends io.grpc.stub.AbstractStub { - private WorkerServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private WorkerServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class WorkerServiceStub extends io.grpc.stub.AbstractAsyncStub { + private WorkerServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected WorkerServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected WorkerServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new WorkerServiceStub(channel, callOptions); } @@ -337,19 +354,15 @@ public void quitWorker(io.grpc.benchmarks.proto.Control.Void request, /** */ - public static final class WorkerServiceBlockingStub extends io.grpc.stub.AbstractStub { - private WorkerServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private WorkerServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class WorkerServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private WorkerServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected WorkerServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected WorkerServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new WorkerServiceBlockingStub(channel, callOptions); } @@ -376,19 +389,15 @@ public io.grpc.benchmarks.proto.Control.Void quitWorker(io.grpc.benchmarks.proto /** */ - public static final class WorkerServiceFutureStub extends io.grpc.stub.AbstractStub { - private WorkerServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private WorkerServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class WorkerServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private WorkerServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected WorkerServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected WorkerServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new WorkerServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp index c4c69b5e251..34cdb734dfd 100644 --- a/compiler/src/java_plugin/cpp/java_generator.cpp +++ b/compiler/src/java_plugin/cpp/java_generator.cpp @@ -474,6 +474,37 @@ static void PrintBindServiceMethodBody(const ServiceDescriptor* service, std::map* vars, Printer* p); +// Prints a StubFactory for given service / stub type. +static void PrintStubFactory( + const ServiceDescriptor* service, + std::map* vars, + Printer* p, StubType type) { + string stub_type_name; + switch (type) { + case ASYNC_CLIENT_IMPL: + stub_type_name = ""; + break; + case FUTURE_CLIENT_IMPL: + stub_type_name = "Future"; + break; + case BLOCKING_CLIENT_IMPL: + stub_type_name = "Blocking"; + break; + default: + GRPC_CODEGEN_FAIL << "Cannot generate StubFactory for StubType: " << type; + } + (*vars)["stub_full_name"] = (*vars)["service_name"] + stub_type_name + "Stub"; + p->Print( + *vars, + "$StubFactory$<$stub_full_name$> factory =\n" + " new $StubFactory$<$stub_full_name$>() {\n" + " @$Override$\n" + " public $stub_full_name$ newStub($Channel$ channel, $CallOptions$ callOptions) {\n" + " return new $stub_full_name$(channel, callOptions);\n" + " }\n" + " };\n"); +} + // Prints a client interface or implementation class, or a server interface. static void PrintStub( const ServiceDescriptor* service, @@ -484,6 +515,7 @@ static void PrintStub( (*vars)["abstract_name"] = service_name + "ImplBase"; string stub_name = service_name; string client_name = service_name; + string stub_base_class_name = "AbstractStub"; CallType call_type; bool impl_base = false; bool interface = false; @@ -495,6 +527,7 @@ static void PrintStub( case ASYNC_CLIENT_IMPL: call_type = ASYNC_CALL; stub_name += "Stub"; + stub_base_class_name = "AbstractAsyncStub"; break; case BLOCKING_CLIENT_INTERFACE: interface = true; @@ -503,6 +536,7 @@ static void PrintStub( call_type = BLOCKING_CALL; stub_name += "BlockingStub"; client_name += "BlockingClient"; + stub_base_class_name = "AbstractBlockingStub"; break; case FUTURE_CLIENT_INTERFACE: interface = true; @@ -511,16 +545,20 @@ static void PrintStub( call_type = FUTURE_CALL; stub_name += "FutureStub"; client_name += "FutureClient"; + stub_base_class_name = "AbstractFutureStub"; break; case ASYNC_INTERFACE: call_type = ASYNC_CALL; interface = true; + stub_name += "Stub"; + stub_base_class_name = "AbstractAsyncStub"; break; default: GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type; } (*vars)["stub_name"] = stub_name; (*vars)["client_name"] = client_name; + (*vars)["stub_base_class_name"] = (*vars)[stub_base_class_name]; // Class head if (!interface) { @@ -534,11 +572,13 @@ static void PrintStub( if (impl_base) { p->Print( *vars, - "public static abstract class $abstract_name$ implements $BindableService$ {\n"); + "public static abstract class $abstract_name$" + " implements $BindableService$ {\n"); } else { p->Print( *vars, - "public static final class $stub_name$ extends $AbstractStub$<$stub_name$> {\n"); + "public static final class $stub_name$" + " extends $stub_base_class_name$<$stub_name$> {\n"); } p->Indent(); @@ -546,15 +586,9 @@ static void PrintStub( if (!impl_base && !interface) { p->Print( *vars, - "private $stub_name$($Channel$ channel) {\n"); - p->Indent(); - p->Print("super(channel);\n"); - p->Outdent(); - p->Print("}\n\n"); - p->Print( - *vars, - "private $stub_name$($Channel$ channel,\n" - " $CallOptions$ callOptions) {\n"); + "private $stub_name$(\n" + " $Channel$ channel, $CallOptions$ callOptions) {" + "\n"); p->Indent(); p->Print("super(channel, callOptions);\n"); p->Outdent(); @@ -562,8 +596,9 @@ static void PrintStub( p->Print( *vars, "@$Override$\n" - "protected $stub_name$ build($Channel$ channel,\n" - " $CallOptions$ callOptions) {\n"); + "protected $stub_name$ build(\n" + " $Channel$ channel, $CallOptions$ callOptions) {" + "\n"); p->Indent(); p->Print( *vars, @@ -1061,9 +1096,8 @@ static void PrintService(const ServiceDescriptor* service, *vars, "public static $service_name$Stub newStub($Channel$ channel) {\n"); p->Indent(); - p->Print( - *vars, - "return new $service_name$Stub(channel);\n"); + PrintStubFactory(service, vars, p, ASYNC_CLIENT_IMPL); + p->Print(*vars, "return $service_name$Stub.newStub(factory, channel);\n"); p->Outdent(); p->Print("}\n\n"); @@ -1075,9 +1109,10 @@ static void PrintService(const ServiceDescriptor* service, "public static $service_name$BlockingStub newBlockingStub(\n" " $Channel$ channel) {\n"); p->Indent(); + PrintStubFactory(service, vars, p, BLOCKING_CLIENT_IMPL); p->Print( *vars, - "return new $service_name$BlockingStub(channel);\n"); + "return $service_name$BlockingStub.newStub(factory, channel);\n"); p->Outdent(); p->Print("}\n\n"); @@ -1089,9 +1124,10 @@ static void PrintService(const ServiceDescriptor* service, "public static $service_name$FutureStub newFutureStub(\n" " $Channel$ channel) {\n"); p->Indent(); + PrintStubFactory(service, vars, p, FUTURE_CLIENT_IMPL); p->Print( *vars, - "return new $service_name$FutureStub(channel);\n"); + "return $service_name$FutureStub.newStub(factory, channel);\n"); p->Outdent(); p->Print("}\n\n"); @@ -1165,6 +1201,10 @@ void GenerateService(const ServiceDescriptor* service, vars["ProtoMethodDescriptorSupplier"] = "io.grpc.protobuf.ProtoMethodDescriptorSupplier"; vars["AbstractStub"] = "io.grpc.stub.AbstractStub"; + vars["AbstractAsyncStub"] = "io.grpc.stub.AbstractAsyncStub"; + vars["AbstractFutureStub"] = "io.grpc.stub.AbstractFutureStub"; + vars["AbstractBlockingStub"] = "io.grpc.stub.AbstractBlockingStub"; + vars["StubFactory"] = "io.grpc.stub.AbstractStub.StubFactory"; vars["RpcMethod"] = "io.grpc.stub.annotations.RpcMethod"; vars["MethodDescriptor"] = "io.grpc.MethodDescriptor"; vars["StreamObserver"] = "io.grpc.stub.StreamObserver"; diff --git a/compiler/src/test/golden/TestDeprecatedService.java.txt b/compiler/src/test/golden/TestDeprecatedService.java.txt index a57999ac0b8..4002f504e66 100644 --- a/compiler/src/test/golden/TestDeprecatedService.java.txt +++ b/compiler/src/test/golden/TestDeprecatedService.java.txt @@ -66,7 +66,14 @@ public final class TestDeprecatedServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestDeprecatedServiceStub newStub(io.grpc.Channel channel) { - return new TestDeprecatedServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestDeprecatedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestDeprecatedServiceStub(channel, callOptions); + } + }; + return TestDeprecatedServiceStub.newStub(factory, channel); } /** @@ -74,7 +81,14 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new TestDeprecatedServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestDeprecatedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestDeprecatedServiceBlockingStub(channel, callOptions); + } + }; + return TestDeprecatedServiceBlockingStub.newStub(factory, channel); } /** @@ -82,7 +96,14 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new TestDeprecatedServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestDeprecatedServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestDeprecatedServiceFutureStub(channel, callOptions); + } + }; + return TestDeprecatedServiceFutureStub.newStub(factory, channel); } /** @@ -123,19 +144,15 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractStub { - private TestDeprecatedServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private TestDeprecatedServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractAsyncStub { + private TestDeprecatedServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceStub(channel, callOptions); } @@ -158,19 +175,15 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractStub { - private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private TestDeprecatedServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceBlockingStub(channel, callOptions); } @@ -192,19 +205,15 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractStub { - private TestDeprecatedServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private TestDeprecatedServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private TestDeprecatedServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index 5479a0ef1c9..d3e5e984649 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -220,7 +220,14 @@ public final class TestServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestServiceStub newStub(io.grpc.Channel channel) { - return new TestServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceStub(channel, callOptions); + } + }; + return TestServiceStub.newStub(factory, channel); } /** @@ -228,7 +235,14 @@ public final class TestServiceGrpc { */ public static TestServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new TestServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceBlockingStub(channel, callOptions); + } + }; + return TestServiceBlockingStub.newStub(factory, channel); } /** @@ -236,7 +250,14 @@ public final class TestServiceGrpc { */ public static TestServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new TestServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceFutureStub(channel, callOptions); + } + }; + return TestServiceFutureStub.newStub(factory, channel); } /** @@ -368,19 +389,15 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceStub extends io.grpc.stub.AbstractStub { - private TestServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceStub extends io.grpc.stub.AbstractAsyncStub { + private TestServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceStub(channel, callOptions); } @@ -465,19 +482,15 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractStub { - private TestServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private TestServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceBlockingStub(channel, callOptions); } @@ -510,19 +523,15 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceFutureStub extends io.grpc.stub.AbstractStub { - private TestServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private TestServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/testLite/golden/TestDeprecatedService.java.txt b/compiler/src/testLite/golden/TestDeprecatedService.java.txt index 6d59a415592..cc2ecb80671 100644 --- a/compiler/src/testLite/golden/TestDeprecatedService.java.txt +++ b/compiler/src/testLite/golden/TestDeprecatedService.java.txt @@ -65,7 +65,14 @@ public final class TestDeprecatedServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestDeprecatedServiceStub newStub(io.grpc.Channel channel) { - return new TestDeprecatedServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestDeprecatedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestDeprecatedServiceStub(channel, callOptions); + } + }; + return TestDeprecatedServiceStub.newStub(factory, channel); } /** @@ -73,7 +80,14 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new TestDeprecatedServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestDeprecatedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestDeprecatedServiceBlockingStub(channel, callOptions); + } + }; + return TestDeprecatedServiceBlockingStub.newStub(factory, channel); } /** @@ -81,7 +95,14 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new TestDeprecatedServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestDeprecatedServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestDeprecatedServiceFutureStub(channel, callOptions); + } + }; + return TestDeprecatedServiceFutureStub.newStub(factory, channel); } /** @@ -122,19 +143,15 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractStub { - private TestDeprecatedServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private TestDeprecatedServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractAsyncStub { + private TestDeprecatedServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceStub(channel, callOptions); } @@ -157,19 +174,15 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractStub { - private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private TestDeprecatedServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceBlockingStub(channel, callOptions); } @@ -191,19 +204,15 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractStub { - private TestDeprecatedServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private TestDeprecatedServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private TestDeprecatedServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt index b1750fc6df5..e79a843236f 100644 --- a/compiler/src/testLite/golden/TestService.java.txt +++ b/compiler/src/testLite/golden/TestService.java.txt @@ -214,7 +214,14 @@ public final class TestServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestServiceStub newStub(io.grpc.Channel channel) { - return new TestServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceStub(channel, callOptions); + } + }; + return TestServiceStub.newStub(factory, channel); } /** @@ -222,7 +229,14 @@ public final class TestServiceGrpc { */ public static TestServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new TestServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceBlockingStub(channel, callOptions); + } + }; + return TestServiceBlockingStub.newStub(factory, channel); } /** @@ -230,7 +244,14 @@ public final class TestServiceGrpc { */ public static TestServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new TestServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceFutureStub(channel, callOptions); + } + }; + return TestServiceFutureStub.newStub(factory, channel); } /** @@ -362,19 +383,15 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceStub extends io.grpc.stub.AbstractStub { - private TestServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceStub extends io.grpc.stub.AbstractAsyncStub { + private TestServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceStub(channel, callOptions); } @@ -459,19 +476,15 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractStub { - private TestServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private TestServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceBlockingStub(channel, callOptions); } @@ -504,19 +517,15 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceFutureStub extends io.grpc.stub.AbstractStub { - private TestServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private TestServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceFutureStub(channel, callOptions); } diff --git a/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java b/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java index 4d3ad18be2b..4c40b2a0f4b 100644 --- a/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java +++ b/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java @@ -62,7 +62,14 @@ io.grpc.lb.v1.LoadBalanceResponse> getBalanceLoadMethod() { * Creates a new async stub that supports all call types for the service */ public static LoadBalancerStub newStub(io.grpc.Channel channel) { - return new LoadBalancerStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoadBalancerStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoadBalancerStub(channel, callOptions); + } + }; + return LoadBalancerStub.newStub(factory, channel); } /** @@ -70,7 +77,14 @@ public static LoadBalancerStub newStub(io.grpc.Channel channel) { */ public static LoadBalancerBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new LoadBalancerBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoadBalancerBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoadBalancerBlockingStub(channel, callOptions); + } + }; + return LoadBalancerBlockingStub.newStub(factory, channel); } /** @@ -78,7 +92,14 @@ public static LoadBalancerBlockingStub newBlockingStub( */ public static LoadBalancerFutureStub newFutureStub( io.grpc.Channel channel) { - return new LoadBalancerFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoadBalancerFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoadBalancerFutureStub(channel, callOptions); + } + }; + return LoadBalancerFutureStub.newStub(factory, channel); } /** @@ -110,19 +131,15 @@ public io.grpc.stub.StreamObserver balanceLoad /** */ - public static final class LoadBalancerStub extends io.grpc.stub.AbstractStub { - private LoadBalancerStub(io.grpc.Channel channel) { - super(channel); - } - - private LoadBalancerStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class LoadBalancerStub extends io.grpc.stub.AbstractAsyncStub { + private LoadBalancerStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadBalancerStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected LoadBalancerStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new LoadBalancerStub(channel, callOptions); } @@ -140,38 +157,30 @@ public io.grpc.stub.StreamObserver balanceLoad /** */ - public static final class LoadBalancerBlockingStub extends io.grpc.stub.AbstractStub { - private LoadBalancerBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private LoadBalancerBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class LoadBalancerBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private LoadBalancerBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadBalancerBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected LoadBalancerBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new LoadBalancerBlockingStub(channel, callOptions); } } /** */ - public static final class LoadBalancerFutureStub extends io.grpc.stub.AbstractStub { - private LoadBalancerFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private LoadBalancerFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class LoadBalancerFutureStub extends io.grpc.stub.AbstractFutureStub { + private LoadBalancerFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadBalancerFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected LoadBalancerFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new LoadBalancerFutureStub(channel, callOptions); } } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java index 2978f9c8cc8..e6c7fcc92bc 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java @@ -93,7 +93,14 @@ io.grpc.testing.integration.Metrics.GaugeResponse> getGetGaugeMethod() { * Creates a new async stub that supports all call types for the service */ public static MetricsServiceStub newStub(io.grpc.Channel channel) { - return new MetricsServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public MetricsServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new MetricsServiceStub(channel, callOptions); + } + }; + return MetricsServiceStub.newStub(factory, channel); } /** @@ -101,7 +108,14 @@ public static MetricsServiceStub newStub(io.grpc.Channel channel) { */ public static MetricsServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new MetricsServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public MetricsServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new MetricsServiceBlockingStub(channel, callOptions); + } + }; + return MetricsServiceBlockingStub.newStub(factory, channel); } /** @@ -109,7 +123,14 @@ public static MetricsServiceBlockingStub newBlockingStub( */ public static MetricsServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new MetricsServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public MetricsServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new MetricsServiceFutureStub(channel, callOptions); + } + }; + return MetricsServiceFutureStub.newStub(factory, channel); } /** @@ -159,19 +180,15 @@ public void getGauge(io.grpc.testing.integration.Metrics.GaugeRequest request, /** */ - public static final class MetricsServiceStub extends io.grpc.stub.AbstractStub { - private MetricsServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private MetricsServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class MetricsServiceStub extends io.grpc.stub.AbstractAsyncStub { + private MetricsServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected MetricsServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected MetricsServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new MetricsServiceStub(channel, callOptions); } @@ -201,19 +218,15 @@ public void getGauge(io.grpc.testing.integration.Metrics.GaugeRequest request, /** */ - public static final class MetricsServiceBlockingStub extends io.grpc.stub.AbstractStub { - private MetricsServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private MetricsServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class MetricsServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private MetricsServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected MetricsServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected MetricsServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new MetricsServiceBlockingStub(channel, callOptions); } @@ -242,19 +255,15 @@ public io.grpc.testing.integration.Metrics.GaugeResponse getGauge(io.grpc.testin /** */ - public static final class MetricsServiceFutureStub extends io.grpc.stub.AbstractStub { - private MetricsServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private MetricsServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class MetricsServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private MetricsServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected MetricsServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected MetricsServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new MetricsServiceFutureStub(channel, callOptions); } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java index 6ecd3208e30..50d29d481f5 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java @@ -96,7 +96,14 @@ io.grpc.testing.integration.Messages.ReconnectInfo> getStopMethod() { * Creates a new async stub that supports all call types for the service */ public static ReconnectServiceStub newStub(io.grpc.Channel channel) { - return new ReconnectServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReconnectServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReconnectServiceStub(channel, callOptions); + } + }; + return ReconnectServiceStub.newStub(factory, channel); } /** @@ -104,7 +111,14 @@ public static ReconnectServiceStub newStub(io.grpc.Channel channel) { */ public static ReconnectServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new ReconnectServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReconnectServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReconnectServiceBlockingStub(channel, callOptions); + } + }; + return ReconnectServiceBlockingStub.newStub(factory, channel); } /** @@ -112,7 +126,14 @@ public static ReconnectServiceBlockingStub newBlockingStub( */ public static ReconnectServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new ReconnectServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReconnectServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReconnectServiceFutureStub(channel, callOptions); + } + }; + return ReconnectServiceFutureStub.newStub(factory, channel); } /** @@ -161,19 +182,15 @@ public void stop(io.grpc.testing.integration.EmptyProtos.Empty request, * A service used to control reconnect server. * */ - public static final class ReconnectServiceStub extends io.grpc.stub.AbstractStub { - private ReconnectServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private ReconnectServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReconnectServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ReconnectServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReconnectServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReconnectServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReconnectServiceStub(channel, callOptions); } @@ -199,19 +216,15 @@ public void stop(io.grpc.testing.integration.EmptyProtos.Empty request, * A service used to control reconnect server. * */ - public static final class ReconnectServiceBlockingStub extends io.grpc.stub.AbstractStub { - private ReconnectServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private ReconnectServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReconnectServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ReconnectServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReconnectServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReconnectServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReconnectServiceBlockingStub(channel, callOptions); } @@ -235,19 +248,15 @@ public io.grpc.testing.integration.Messages.ReconnectInfo stop(io.grpc.testing.i * A service used to control reconnect server. * */ - public static final class ReconnectServiceFutureStub extends io.grpc.stub.AbstractStub { - private ReconnectServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private ReconnectServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReconnectServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ReconnectServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReconnectServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReconnectServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReconnectServiceFutureStub(channel, callOptions); } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java index faa8925faa8..e300c5f6b20 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java @@ -283,7 +283,14 @@ io.grpc.testing.integration.EmptyProtos.Empty> getUnimplementedCallMethod() { * Creates a new async stub that supports all call types for the service */ public static TestServiceStub newStub(io.grpc.Channel channel) { - return new TestServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceStub(channel, callOptions); + } + }; + return TestServiceStub.newStub(factory, channel); } /** @@ -291,7 +298,14 @@ public static TestServiceStub newStub(io.grpc.Channel channel) { */ public static TestServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new TestServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceBlockingStub(channel, callOptions); + } + }; + return TestServiceBlockingStub.newStub(factory, channel); } /** @@ -299,7 +313,14 @@ public static TestServiceBlockingStub newBlockingStub( */ public static TestServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new TestServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public TestServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new TestServiceFutureStub(channel, callOptions); + } + }; + return TestServiceFutureStub.newStub(factory, channel); } /** @@ -468,19 +489,15 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * performance with various types of payload. * */ - public static final class TestServiceStub extends io.grpc.stub.AbstractStub { - private TestServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceStub extends io.grpc.stub.AbstractAsyncStub { + private TestServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceStub(channel, callOptions); } @@ -589,19 +606,15 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * performance with various types of payload. * */ - public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractStub { - private TestServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private TestServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceBlockingStub(channel, callOptions); } @@ -667,19 +680,15 @@ public io.grpc.testing.integration.EmptyProtos.Empty unimplementedCall(io.grpc.t * performance with various types of payload. * */ - public static final class TestServiceFutureStub extends io.grpc.stub.AbstractStub { - private TestServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private TestServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class TestServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private TestServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected TestServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new TestServiceFutureStub(channel, callOptions); } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java index 156321975d6..09cd8e9ef13 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java @@ -66,7 +66,14 @@ io.grpc.testing.integration.EmptyProtos.Empty> getUnimplementedCallMethod() { * Creates a new async stub that supports all call types for the service */ public static UnimplementedServiceStub newStub(io.grpc.Channel channel) { - return new UnimplementedServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public UnimplementedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new UnimplementedServiceStub(channel, callOptions); + } + }; + return UnimplementedServiceStub.newStub(factory, channel); } /** @@ -74,7 +81,14 @@ public static UnimplementedServiceStub newStub(io.grpc.Channel channel) { */ public static UnimplementedServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new UnimplementedServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public UnimplementedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new UnimplementedServiceBlockingStub(channel, callOptions); + } + }; + return UnimplementedServiceBlockingStub.newStub(factory, channel); } /** @@ -82,7 +96,14 @@ public static UnimplementedServiceBlockingStub newBlockingStub( */ public static UnimplementedServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new UnimplementedServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public UnimplementedServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new UnimplementedServiceFutureStub(channel, callOptions); + } + }; + return UnimplementedServiceFutureStub.newStub(factory, channel); } /** @@ -122,19 +143,15 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * that case. * */ - public static final class UnimplementedServiceStub extends io.grpc.stub.AbstractStub { - private UnimplementedServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private UnimplementedServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class UnimplementedServiceStub extends io.grpc.stub.AbstractAsyncStub { + private UnimplementedServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected UnimplementedServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected UnimplementedServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new UnimplementedServiceStub(channel, callOptions); } @@ -156,19 +173,15 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * that case. * */ - public static final class UnimplementedServiceBlockingStub extends io.grpc.stub.AbstractStub { - private UnimplementedServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private UnimplementedServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class UnimplementedServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private UnimplementedServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected UnimplementedServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected UnimplementedServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new UnimplementedServiceBlockingStub(channel, callOptions); } @@ -189,19 +202,15 @@ public io.grpc.testing.integration.EmptyProtos.Empty unimplementedCall(io.grpc.t * that case. * */ - public static final class UnimplementedServiceFutureStub extends io.grpc.stub.AbstractStub { - private UnimplementedServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private UnimplementedServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class UnimplementedServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private UnimplementedServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected UnimplementedServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected UnimplementedServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new UnimplementedServiceFutureStub(channel, callOptions); } diff --git a/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java b/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java index 165eec264e1..d45eb53587e 100644 --- a/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java +++ b/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java @@ -252,7 +252,14 @@ io.grpc.channelz.v1.GetSocketResponse> getGetSocketMethod() { * Creates a new async stub that supports all call types for the service */ public static ChannelzStub newStub(io.grpc.Channel channel) { - return new ChannelzStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ChannelzStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ChannelzStub(channel, callOptions); + } + }; + return ChannelzStub.newStub(factory, channel); } /** @@ -260,7 +267,14 @@ public static ChannelzStub newStub(io.grpc.Channel channel) { */ public static ChannelzBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new ChannelzBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ChannelzBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ChannelzBlockingStub(channel, callOptions); + } + }; + return ChannelzBlockingStub.newStub(factory, channel); } /** @@ -268,7 +282,14 @@ public static ChannelzBlockingStub newBlockingStub( */ public static ChannelzFutureStub newFutureStub( io.grpc.Channel channel) { - return new ChannelzFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ChannelzFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ChannelzFutureStub(channel, callOptions); + } + }; + return ChannelzFutureStub.newStub(factory, channel); } /** @@ -411,19 +432,15 @@ public void getSocket(io.grpc.channelz.v1.GetSocketRequest request, * information. * */ - public static final class ChannelzStub extends io.grpc.stub.AbstractStub { - private ChannelzStub(io.grpc.Channel channel) { - super(channel); - } - - private ChannelzStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ChannelzStub extends io.grpc.stub.AbstractAsyncStub { + private ChannelzStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ChannelzStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ChannelzStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ChannelzStub(channel, callOptions); } @@ -512,19 +529,15 @@ public void getSocket(io.grpc.channelz.v1.GetSocketRequest request, * information. * */ - public static final class ChannelzBlockingStub extends io.grpc.stub.AbstractStub { - private ChannelzBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private ChannelzBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ChannelzBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ChannelzBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ChannelzBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ChannelzBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ChannelzBlockingStub(channel, callOptions); } @@ -606,19 +619,15 @@ public io.grpc.channelz.v1.GetSocketResponse getSocket(io.grpc.channelz.v1.GetSo * information. * */ - public static final class ChannelzFutureStub extends io.grpc.stub.AbstractStub { - private ChannelzFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private ChannelzFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ChannelzFutureStub extends io.grpc.stub.AbstractFutureStub { + private ChannelzFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ChannelzFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ChannelzFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ChannelzFutureStub(channel, callOptions); } diff --git a/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java b/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java index 93b8abb28ef..14457d12c7f 100644 --- a/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java +++ b/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java @@ -93,7 +93,14 @@ io.grpc.health.v1.HealthCheckResponse> getWatchMethod() { * Creates a new async stub that supports all call types for the service */ public static HealthStub newStub(io.grpc.Channel channel) { - return new HealthStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public HealthStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HealthStub(channel, callOptions); + } + }; + return HealthStub.newStub(factory, channel); } /** @@ -101,7 +108,14 @@ public static HealthStub newStub(io.grpc.Channel channel) { */ public static HealthBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new HealthBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public HealthBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HealthBlockingStub(channel, callOptions); + } + }; + return HealthBlockingStub.newStub(factory, channel); } /** @@ -109,7 +123,14 @@ public static HealthBlockingStub newBlockingStub( */ public static HealthFutureStub newFutureStub( io.grpc.Channel channel) { - return new HealthFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public HealthFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new HealthFutureStub(channel, callOptions); + } + }; + return HealthFutureStub.newStub(factory, channel); } /** @@ -171,19 +192,15 @@ public void watch(io.grpc.health.v1.HealthCheckRequest request, /** */ - public static final class HealthStub extends io.grpc.stub.AbstractStub { - private HealthStub(io.grpc.Channel channel) { - super(channel); - } - - private HealthStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class HealthStub extends io.grpc.stub.AbstractAsyncStub { + private HealthStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HealthStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected HealthStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new HealthStub(channel, callOptions); } @@ -225,19 +242,15 @@ public void watch(io.grpc.health.v1.HealthCheckRequest request, /** */ - public static final class HealthBlockingStub extends io.grpc.stub.AbstractStub { - private HealthBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private HealthBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class HealthBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private HealthBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HealthBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected HealthBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new HealthBlockingStub(channel, callOptions); } @@ -278,19 +291,15 @@ public java.util.Iterator watch( /** */ - public static final class HealthFutureStub extends io.grpc.stub.AbstractStub { - private HealthFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private HealthFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class HealthFutureStub extends io.grpc.stub.AbstractFutureStub { + private HealthFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HealthFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected HealthFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new HealthFutureStub(channel, callOptions); } diff --git a/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java b/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java index 035d177e2d5..f85cbfdba70 100644 --- a/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java +++ b/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java @@ -62,7 +62,14 @@ io.grpc.reflection.v1alpha.ServerReflectionResponse> getServerReflectionInfoMeth * Creates a new async stub that supports all call types for the service */ public static ServerReflectionStub newStub(io.grpc.Channel channel) { - return new ServerReflectionStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ServerReflectionStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ServerReflectionStub(channel, callOptions); + } + }; + return ServerReflectionStub.newStub(factory, channel); } /** @@ -70,7 +77,14 @@ public static ServerReflectionStub newStub(io.grpc.Channel channel) { */ public static ServerReflectionBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new ServerReflectionBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ServerReflectionBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ServerReflectionBlockingStub(channel, callOptions); + } + }; + return ServerReflectionBlockingStub.newStub(factory, channel); } /** @@ -78,7 +92,14 @@ public static ServerReflectionBlockingStub newBlockingStub( */ public static ServerReflectionFutureStub newFutureStub( io.grpc.Channel channel) { - return new ServerReflectionFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ServerReflectionFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ServerReflectionFutureStub(channel, callOptions); + } + }; + return ServerReflectionFutureStub.newStub(factory, channel); } /** @@ -111,19 +132,15 @@ public io.grpc.stub.StreamObserver { - private ServerReflectionStub(io.grpc.Channel channel) { - super(channel); - } - - private ServerReflectionStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ServerReflectionStub extends io.grpc.stub.AbstractAsyncStub { + private ServerReflectionStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ServerReflectionStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ServerReflectionStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ServerReflectionStub(channel, callOptions); } @@ -142,38 +159,30 @@ public io.grpc.stub.StreamObserver { - private ServerReflectionBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private ServerReflectionBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ServerReflectionBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ServerReflectionBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ServerReflectionBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ServerReflectionBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ServerReflectionBlockingStub(channel, callOptions); } } /** */ - public static final class ServerReflectionFutureStub extends io.grpc.stub.AbstractStub { - private ServerReflectionFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private ServerReflectionFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ServerReflectionFutureStub extends io.grpc.stub.AbstractFutureStub { + private ServerReflectionFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ServerReflectionFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ServerReflectionFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ServerReflectionFutureStub(channel, callOptions); } } diff --git a/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java b/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java index 1b5ab5c12cb..be673b3939c 100644 --- a/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java +++ b/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java @@ -65,7 +65,14 @@ io.grpc.reflection.testing.DynamicReply> getMethodMethod() { * Creates a new async stub that supports all call types for the service */ public static AnotherDynamicServiceStub newStub(io.grpc.Channel channel) { - return new AnotherDynamicServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public AnotherDynamicServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AnotherDynamicServiceStub(channel, callOptions); + } + }; + return AnotherDynamicServiceStub.newStub(factory, channel); } /** @@ -73,7 +80,14 @@ public static AnotherDynamicServiceStub newStub(io.grpc.Channel channel) { */ public static AnotherDynamicServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new AnotherDynamicServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public AnotherDynamicServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AnotherDynamicServiceBlockingStub(channel, callOptions); + } + }; + return AnotherDynamicServiceBlockingStub.newStub(factory, channel); } /** @@ -81,7 +95,14 @@ public static AnotherDynamicServiceBlockingStub newBlockingStub( */ public static AnotherDynamicServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new AnotherDynamicServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public AnotherDynamicServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AnotherDynamicServiceFutureStub(channel, callOptions); + } + }; + return AnotherDynamicServiceFutureStub.newStub(factory, channel); } /** @@ -119,19 +140,15 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * AnotherDynamicService * */ - public static final class AnotherDynamicServiceStub extends io.grpc.stub.AbstractStub { - private AnotherDynamicServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private AnotherDynamicServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class AnotherDynamicServiceStub extends io.grpc.stub.AbstractAsyncStub { + private AnotherDynamicServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AnotherDynamicServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected AnotherDynamicServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new AnotherDynamicServiceStub(channel, callOptions); } @@ -152,19 +169,15 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * AnotherDynamicService * */ - public static final class AnotherDynamicServiceBlockingStub extends io.grpc.stub.AbstractStub { - private AnotherDynamicServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private AnotherDynamicServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class AnotherDynamicServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private AnotherDynamicServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AnotherDynamicServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected AnotherDynamicServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new AnotherDynamicServiceBlockingStub(channel, callOptions); } @@ -184,19 +197,15 @@ public io.grpc.reflection.testing.DynamicReply method(io.grpc.reflection.testing * AnotherDynamicService * */ - public static final class AnotherDynamicServiceFutureStub extends io.grpc.stub.AbstractStub { - private AnotherDynamicServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private AnotherDynamicServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class AnotherDynamicServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private AnotherDynamicServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AnotherDynamicServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected AnotherDynamicServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new AnotherDynamicServiceFutureStub(channel, callOptions); } diff --git a/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java b/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java index 1b5e7c78c89..a80ac5fefb2 100644 --- a/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java +++ b/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java @@ -65,7 +65,14 @@ io.grpc.reflection.testing.DynamicReply> getMethodMethod() { * Creates a new async stub that supports all call types for the service */ public static DynamicServiceStub newStub(io.grpc.Channel channel) { - return new DynamicServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public DynamicServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new DynamicServiceStub(channel, callOptions); + } + }; + return DynamicServiceStub.newStub(factory, channel); } /** @@ -73,7 +80,14 @@ public static DynamicServiceStub newStub(io.grpc.Channel channel) { */ public static DynamicServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new DynamicServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public DynamicServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new DynamicServiceBlockingStub(channel, callOptions); + } + }; + return DynamicServiceBlockingStub.newStub(factory, channel); } /** @@ -81,7 +95,14 @@ public static DynamicServiceBlockingStub newBlockingStub( */ public static DynamicServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new DynamicServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public DynamicServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new DynamicServiceFutureStub(channel, callOptions); + } + }; + return DynamicServiceFutureStub.newStub(factory, channel); } /** @@ -119,19 +140,15 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * A DynamicService * */ - public static final class DynamicServiceStub extends io.grpc.stub.AbstractStub { - private DynamicServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private DynamicServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class DynamicServiceStub extends io.grpc.stub.AbstractAsyncStub { + private DynamicServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected DynamicServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected DynamicServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new DynamicServiceStub(channel, callOptions); } @@ -152,19 +169,15 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * A DynamicService * */ - public static final class DynamicServiceBlockingStub extends io.grpc.stub.AbstractStub { - private DynamicServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private DynamicServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class DynamicServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private DynamicServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected DynamicServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected DynamicServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new DynamicServiceBlockingStub(channel, callOptions); } @@ -184,19 +197,15 @@ public io.grpc.reflection.testing.DynamicReply method(io.grpc.reflection.testing * A DynamicService * */ - public static final class DynamicServiceFutureStub extends io.grpc.stub.AbstractStub { - private DynamicServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private DynamicServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class DynamicServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private DynamicServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected DynamicServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected DynamicServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new DynamicServiceFutureStub(channel, callOptions); } diff --git a/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java b/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java index f88764670d1..ed328240284 100644 --- a/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java +++ b/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java @@ -62,7 +62,14 @@ io.grpc.reflection.testing.Reply> getMethodMethod() { * Creates a new async stub that supports all call types for the service */ public static ReflectableServiceStub newStub(io.grpc.Channel channel) { - return new ReflectableServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReflectableServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReflectableServiceStub(channel, callOptions); + } + }; + return ReflectableServiceStub.newStub(factory, channel); } /** @@ -70,7 +77,14 @@ public static ReflectableServiceStub newStub(io.grpc.Channel channel) { */ public static ReflectableServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new ReflectableServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReflectableServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReflectableServiceBlockingStub(channel, callOptions); + } + }; + return ReflectableServiceBlockingStub.newStub(factory, channel); } /** @@ -78,7 +92,14 @@ public static ReflectableServiceBlockingStub newBlockingStub( */ public static ReflectableServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new ReflectableServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ReflectableServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ReflectableServiceFutureStub(channel, callOptions); + } + }; + return ReflectableServiceFutureStub.newStub(factory, channel); } /** @@ -107,19 +128,15 @@ public void method(io.grpc.reflection.testing.Request request, /** */ - public static final class ReflectableServiceStub extends io.grpc.stub.AbstractStub { - private ReflectableServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private ReflectableServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReflectableServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ReflectableServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReflectableServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReflectableServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReflectableServiceStub(channel, callOptions); } @@ -134,19 +151,15 @@ public void method(io.grpc.reflection.testing.Request request, /** */ - public static final class ReflectableServiceBlockingStub extends io.grpc.stub.AbstractStub { - private ReflectableServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private ReflectableServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReflectableServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ReflectableServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReflectableServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReflectableServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReflectableServiceBlockingStub(channel, callOptions); } @@ -160,19 +173,15 @@ public io.grpc.reflection.testing.Reply method(io.grpc.reflection.testing.Reques /** */ - public static final class ReflectableServiceFutureStub extends io.grpc.stub.AbstractStub { - private ReflectableServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private ReflectableServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class ReflectableServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ReflectableServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReflectableServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected ReflectableServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new ReflectableServiceFutureStub(channel, callOptions); } diff --git a/stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java b/stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java new file mode 100644 index 00000000000..2b12b39921d --- /dev/null +++ b/stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java @@ -0,0 +1,69 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.stub.ClientCalls.StubType; +import javax.annotation.CheckReturnValue; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Stub implementations for async stubs. + * + *

    DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder + * to create a real channel suitable for testing. It is also possible to mock Channel instead. + * + * @since 1.25.0 + */ +@ThreadSafe +@CheckReturnValue +public abstract class AbstractAsyncStub> extends AbstractStub { + + protected AbstractAsyncStub(Channel channel, CallOptions callOptions) { + super(channel, callOptions); + } + + /** + * Returns a new async stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create an async stub + * @param channel the channel that this stub will use to do communications + */ + public static > T newStub( + StubFactory factory, Channel channel) { + return newStub(factory, channel, CallOptions.DEFAULT); + } + + /** + * Returns a new async stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create an async stub + * @param channel the channel that this stub will use to do communications + * @param callOptions the runtime call options to be applied to every call on this stub + */ + public static > T newStub( + StubFactory factory, Channel channel, CallOptions callOptions) { + T stub = factory.newStub( + channel, callOptions.withOption(ClientCalls.STUB_TYPE_OPTION, StubType.ASYNC)); + assert stub instanceof AbstractAsyncStub + : String.format("Expected AbstractAsyncStub, but got %s.", stub.getClass()); + return stub; + } +} diff --git a/stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java b/stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java new file mode 100644 index 00000000000..8b13e0d012f --- /dev/null +++ b/stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.stub.ClientCalls.StubType; +import javax.annotation.CheckReturnValue; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Stub implementations for blocking stubs. + * + *

    DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder + * to create a real channel suitable for testing. It is also possible to mock Channel instead. + * + * @since 1.25.0 + */ +@ThreadSafe +@CheckReturnValue +public abstract class AbstractBlockingStub> + extends AbstractStub { + + protected AbstractBlockingStub(Channel channel, CallOptions callOptions) { + super(channel, callOptions); + } + + /** + * Returns a new blocking stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create a blocking stub + * @param channel the channel that this stub will use to do communications + */ + public static > T newStub( + StubFactory factory, Channel channel) { + return newStub(factory, channel, CallOptions.DEFAULT); + } + + /** + * Returns a new blocking stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create a blocking stub + * @param channel the channel that this stub will use to do communications + * @param callOptions the runtime call options to be applied to every call on this stub + */ + public static > T newStub( + StubFactory factory, Channel channel, CallOptions callOptions) { + T stub = factory.newStub( + channel, callOptions.withOption(ClientCalls.STUB_TYPE_OPTION, StubType.BLOCKING)); + assert stub instanceof AbstractBlockingStub + : String.format("Expected AbstractBlockingStub, but got %s.", stub.getClass()); + return stub; + } +} diff --git a/stub/src/main/java/io/grpc/stub/AbstractFutureStub.java b/stub/src/main/java/io/grpc/stub/AbstractFutureStub.java new file mode 100644 index 00000000000..86d37eddf0a --- /dev/null +++ b/stub/src/main/java/io/grpc/stub/AbstractFutureStub.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.stub.ClientCalls.StubType; +import javax.annotation.CheckReturnValue; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Stub implementations for future stubs. + * + *

    DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder + * to create a real channel suitable for testing. It is also possible to mock Channel instead. + * + * @since 1.25.0 + */ +@ThreadSafe +@CheckReturnValue +public abstract class AbstractFutureStub> extends AbstractStub { + + protected AbstractFutureStub(Channel channel, CallOptions callOptions) { + super(channel, callOptions); + } + + /** + * Returns a new future stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create a future stub + * @param channel the channel that this stub will use to do communications + */ + public static > T newStub( + StubFactory factory, Channel channel) { + return newStub(factory, channel, CallOptions.DEFAULT); + } + + /** + * Returns a new future stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create a future stub + * @param channel the channel that this stub will use to do communications + * @param callOptions the runtime call options to be applied to every call on this stub + * @return a future stub + */ + public static > T newStub( + StubFactory factory, Channel channel, CallOptions callOptions) { + T stub = factory.newStub( + channel, callOptions.withOption(ClientCalls.STUB_TYPE_OPTION, StubType.FUTURE)); + assert stub instanceof AbstractFutureStub + : String.format("Expected AbstractFutureStub, but got %s.", stub.getClass()); + return stub; + } +} diff --git a/stub/src/main/java/io/grpc/stub/AbstractStub.java b/stub/src/main/java/io/grpc/stub/AbstractStub.java index 346512adc03..f3a16109dae 100644 --- a/stub/src/main/java/io/grpc/stub/AbstractStub.java +++ b/stub/src/main/java/io/grpc/stub/AbstractStub.java @@ -101,6 +101,31 @@ public final CallOptions getCallOptions() { */ protected abstract S build(Channel channel, CallOptions callOptions); + /** + * Returns a new stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create a stub + * @param channel the channel that this stub will use to do communications + */ + public static > T newStub( + StubFactory factory, Channel channel) { + return newStub(factory, channel, CallOptions.DEFAULT); + } + + /** + * Returns a new stub with the given channel for the provided method configurations. + * + * @since 1.25.0 + * @param factory the factory to create a stub + * @param channel the channel that this stub will use to do communications + * @param callOptions the runtime call options to be applied to every call on this stub + */ + public static > T newStub( + StubFactory factory, Channel channel, CallOptions callOptions) { + return factory.newStub(channel, callOptions); + } + /** * Returns a new stub with an absolute deadline. * @@ -224,4 +249,13 @@ public final S withMaxInboundMessageSize(int maxSize) { public final S withMaxOutboundMessageSize(int maxSize) { return build(channel, callOptions.withMaxOutboundMessageSize(maxSize)); } + + /** + * A factory class for stub. + * + * @since 1.25.0 + */ + public interface StubFactory> { + T newStub(Channel channel, CallOptions callOptions); + } } diff --git a/stub/src/main/java/io/grpc/stub/ClientCalls.java b/stub/src/main/java/io/grpc/stub/ClientCalls.java index cf770a991e1..4c78b1b6520 100644 --- a/stub/src/main/java/io/grpc/stub/ClientCalls.java +++ b/stub/src/main/java/io/grpc/stub/ClientCalls.java @@ -704,4 +704,14 @@ public void execute(Runnable runnable) { LockSupport.unpark(waiter); // no-op if null } } + + enum StubType { + BLOCKING, FUTURE, ASYNC + } + + /** + * Internal {@link CallOptions.Key} to indicate stub types. + */ + static final CallOptions.Key STUB_TYPE_OPTION = + CallOptions.Key.create("internal-stub-type"); } diff --git a/stub/src/main/java/io/grpc/stub/InternalClientCalls.java b/stub/src/main/java/io/grpc/stub/InternalClientCalls.java new file mode 100644 index 00000000000..abd7d07585b --- /dev/null +++ b/stub/src/main/java/io/grpc/stub/InternalClientCalls.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import io.grpc.CallOptions; +import io.grpc.Internal; + +/** + * Internal {@link ClientCalls} accessor. This is intended for usage internal to the gRPC + * team. If you *really* think you need to use this, contact the gRPC team first. + */ +@Internal +public final class InternalClientCalls { + + /** Internal accessor for {@link ClientCalls#STUB_TYPE_OPTION}. */ + public static CallOptions.Key getStubTypeOption() { + return ClientCalls.STUB_TYPE_OPTION; + } + + /** Returns {@link StubType} from call options. */ + public static StubType getStubType(CallOptions callOptions) { + return StubType.of(callOptions.getOption(ClientCalls.STUB_TYPE_OPTION)); + } + + /** Companion enum for internal enum {@link ClientCalls.StubType}. */ + public enum StubType { + BLOCKING(ClientCalls.StubType.BLOCKING), + ASYNC(ClientCalls.StubType.ASYNC), + FUTURE(ClientCalls.StubType.FUTURE); + + private final ClientCalls.StubType internalType; + + StubType(ClientCalls.StubType internalType) { + this.internalType = internalType; + } + + /** Returns companion enum value of passed internal enum equivalent. */ + public static StubType of(ClientCalls.StubType internal) { + for (StubType value : StubType.values()) { + if (value.internalType == internal) { + return value; + } + } + throw new AssertionError("Unknown StubType: " + internal.name()); + } + } +} diff --git a/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java new file mode 100644 index 00000000000..3cb13e9b368 --- /dev/null +++ b/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.stub.AbstractAsyncStubTest.NoopAsyncStub; +import io.grpc.stub.AbstractBlockingStubTest.NoopBlockingStub; +import io.grpc.stub.AbstractFutureStubTest.NoopFutureStub; +import io.grpc.stub.AbstractStub.StubFactory; +import io.grpc.stub.ClientCalls.StubType; +import org.junit.Test; + +public class AbstractAsyncStubTest extends BaseAbstractStubTest { + + @Override + NoopAsyncStub create(Channel channel, CallOptions callOptions) { + return new NoopAsyncStub(channel, callOptions); + } + + @Test + public void defaultCallOptions() { + NoopAsyncStub stub = NoopAsyncStub.newStub(new StubFactory() { + @Override + public NoopAsyncStub newStub(Channel channel, CallOptions callOptions) { + return create(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + + assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) + .isEqualTo(StubType.ASYNC); + } + + @Test + @SuppressWarnings("AssertionFailureIgnored") + public void newStub_futureStub_throwsException() { + try { + NoopFutureStub unused = NoopAsyncStub.newStub(new StubFactory() { + @Override + public NoopFutureStub newStub(Channel channel, CallOptions callOptions) { + return new NoopFutureStub(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + fail("should not reach here"); + } catch (AssertionError e) { + assertThat(e).hasMessageThat().startsWith("Expected AbstractAsyncStub"); + } + } + + @Test + @SuppressWarnings("AssertionFailureIgnored") + public void newStub_blockingStub_throwsException() { + try { + NoopBlockingStub unused = NoopAsyncStub.newStub(new StubFactory() { + @Override + public NoopBlockingStub newStub(Channel channel, CallOptions callOptions) { + return new NoopBlockingStub(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + fail("should not reach here"); + } catch (AssertionError e) { + assertThat(e).hasMessageThat().startsWith("Expected AbstractAsyncStub"); + } + } + + static class NoopAsyncStub extends AbstractAsyncStub { + + NoopAsyncStub(Channel channel, CallOptions options) { + super(channel, options); + } + + @Override + protected NoopAsyncStub build(Channel channel, CallOptions callOptions) { + return new NoopAsyncStub(channel, callOptions); + } + } +} diff --git a/stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java new file mode 100644 index 00000000000..a3477da2bb5 --- /dev/null +++ b/stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java @@ -0,0 +1,97 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.stub.AbstractAsyncStubTest.NoopAsyncStub; +import io.grpc.stub.AbstractBlockingStubTest.NoopBlockingStub; +import io.grpc.stub.AbstractFutureStubTest.NoopFutureStub; +import io.grpc.stub.AbstractStub.StubFactory; +import io.grpc.stub.ClientCalls.StubType; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class AbstractBlockingStubTest extends BaseAbstractStubTest { + + @Override + NoopBlockingStub create(Channel channel, CallOptions callOptions) { + return new NoopBlockingStub(channel, callOptions); + } + + @Test + public void defaultCallOptions() { + NoopBlockingStub stub = NoopBlockingStub.newStub(new StubFactory() { + @Override + public NoopBlockingStub newStub(Channel channel, CallOptions callOptions) { + return create(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + + assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) + .isEqualTo(StubType.BLOCKING); + } + + @Test + @SuppressWarnings("AssertionFailureIgnored") + public void newStub_asyncStub_throwsException() { + try { + NoopAsyncStub unused = NoopBlockingStub.newStub(new StubFactory() { + @Override + public NoopAsyncStub newStub(Channel channel, CallOptions callOptions) { + return new NoopAsyncStub(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + fail("should not reach here"); + } catch (AssertionError e) { + assertThat(e).hasMessageThat().startsWith("Expected AbstractBlockingStub"); + } + } + + @Test + @SuppressWarnings("AssertionFailureIgnored") + public void newStub_futureStub_throwsException() { + try { + NoopFutureStub unused = NoopBlockingStub.newStub(new StubFactory() { + @Override + public NoopFutureStub newStub(Channel channel, CallOptions callOptions) { + return new NoopFutureStub(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + fail("should not reach here"); + } catch (AssertionError e) { + assertThat(e).hasMessageThat().startsWith("Expected AbstractBlockingStub"); + } + } + + static class NoopBlockingStub extends AbstractBlockingStub { + + NoopBlockingStub(Channel channel, CallOptions options) { + super(channel, options); + } + + @Override + protected NoopBlockingStub build(Channel channel, CallOptions callOptions) { + return new NoopBlockingStub(channel, callOptions); + } + } +} \ No newline at end of file diff --git a/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java new file mode 100644 index 00000000000..c7afe3f77bd --- /dev/null +++ b/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java @@ -0,0 +1,94 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.fail; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.stub.AbstractAsyncStubTest.NoopAsyncStub; +import io.grpc.stub.AbstractBlockingStubTest.NoopBlockingStub; +import io.grpc.stub.AbstractFutureStubTest.NoopFutureStub; +import io.grpc.stub.AbstractStub.StubFactory; +import io.grpc.stub.ClientCalls.StubType; +import org.junit.Test; + +public class AbstractFutureStubTest extends BaseAbstractStubTest { + + @Override + NoopFutureStub create(Channel channel, CallOptions callOptions) { + return new NoopFutureStub(channel, callOptions); + } + + @Test + public void defaultCallOptions() { + NoopFutureStub stub = NoopFutureStub.newStub(new StubFactory() { + @Override + public NoopFutureStub newStub(Channel channel, CallOptions callOptions) { + return create(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + + assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) + .isEqualTo(StubType.FUTURE); + } + + @Test + @SuppressWarnings("AssertionFailureIgnored") + public void newStub_asyncStub_throwsException() { + try { + NoopAsyncStub unused = NoopFutureStub.newStub(new StubFactory() { + @Override + public NoopAsyncStub newStub(Channel channel, CallOptions callOptions) { + return new NoopAsyncStub(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + fail("should not reach here"); + } catch (AssertionError e) { + assertThat(e).hasMessageThat().startsWith("Expected AbstractFutureStub"); + } + } + + @Test + @SuppressWarnings("AssertionFailureIgnored") + public void newStub_blockingStub_throwsException() { + try { + NoopBlockingStub unused = NoopFutureStub.newStub(new StubFactory() { + @Override + public NoopBlockingStub newStub(Channel channel, CallOptions callOptions) { + return new NoopBlockingStub(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + fail("should not reach here"); + } catch (AssertionError e) { + assertThat(e).hasMessageThat().startsWith("Expected AbstractFutureStub"); + } + } + + static class NoopFutureStub extends AbstractFutureStub { + + NoopFutureStub(Channel channel, CallOptions options) { + super(channel, options); + } + + @Override + protected NoopFutureStub build(Channel channel, CallOptions callOptions) { + return new NoopFutureStub(channel, callOptions); + } + } +} \ No newline at end of file diff --git a/stub/src/test/java/io/grpc/stub/AbstractStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractStubTest.java index 7c73f69d18d..9006b8679e4 100644 --- a/stub/src/test/java/io/grpc/stub/AbstractStubTest.java +++ b/stub/src/test/java/io/grpc/stub/AbstractStubTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 The gRPC Authors + * Copyright 2019 The gRPC Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,65 +16,39 @@ package io.grpc.stub; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; +import static com.google.common.truth.Truth.assertThat; import io.grpc.CallOptions; import io.grpc.Channel; -import java.util.concurrent.Executor; -import org.junit.Before; +import io.grpc.stub.AbstractStub.StubFactory; +import io.grpc.stub.AbstractStubTest.NoopStub; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; @RunWith(JUnit4.class) -public class AbstractStubTest { +public class AbstractStubTest extends BaseAbstractStubTest { - @Mock - Channel channel; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - @Test(expected = NullPointerException.class) - public void channelMustNotBeNull() { - new NoopStub(null); - } - - @Test(expected = NullPointerException.class) - public void callOptionsMustNotBeNull() { - new NoopStub(channel, null); + @Override + NoopStub create(Channel channel, CallOptions callOptions) { + return new NoopStub(channel, callOptions); } - @Test(expected = NullPointerException.class) - public void channelMustNotBeNull2() { - new NoopStub(null, CallOptions.DEFAULT); - } - - @Test() - public void withWaitForReady() { - NoopStub stub = new NoopStub(channel); - CallOptions callOptions = stub.getCallOptions(); - assertFalse(callOptions.isWaitForReady()); - - stub = stub.withWaitForReady(); - callOptions = stub.getCallOptions(); - assertTrue(callOptions.isWaitForReady()); + @Test + public void defaultCallOptions() { + NoopStub stub = NoopStub.newStub(new StubFactory() { + @Override + public NoopStub newStub(Channel channel, CallOptions callOptions) { + return create(channel, callOptions); + } + }, channel, CallOptions.DEFAULT); + + assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) + .isNull(); } class NoopStub extends AbstractStub { - NoopStub(Channel channel) { - super(channel); - } - NoopStub(Channel channel, CallOptions options) { super(channel, options); } @@ -84,18 +58,5 @@ protected NoopStub build(Channel channel, CallOptions callOptions) { return new NoopStub(channel, callOptions); } } - - @Test - public void withExecutor() { - NoopStub stub = new NoopStub(channel); - CallOptions callOptions = stub.getCallOptions(); - - assertNull(callOptions.getExecutor()); - - Executor executor = mock(Executor.class); - stub = stub.withExecutor(executor); - callOptions = stub.getCallOptions(); - - assertEquals(callOptions.getExecutor(), executor); - } } + diff --git a/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java b/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java new file mode 100644 index 00000000000..e2219b9ef67 --- /dev/null +++ b/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java @@ -0,0 +1,86 @@ +/* + * Copyright 2016 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.stub; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import java.util.concurrent.Executor; +import javax.annotation.Nullable; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +/** Standard unit tests for AbstractStub and its subclasses. */ +abstract class BaseAbstractStubTest> { + + @Mock + Channel channel; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + } + + T create(Channel channel) { + return create(channel, CallOptions.DEFAULT); + } + + abstract T create(@Nullable Channel channel, @Nullable CallOptions callOptions); + + @Test(expected = NullPointerException.class) + public void callOptionsMustNotBeNull() { + create(channel, null); + throw new NullPointerException(); + } + + @Test(expected = NullPointerException.class) + public void channelMustNotBeNull2() { + create(null, CallOptions.DEFAULT); + } + + @Test + public void withWaitForReady() { + T stub = create(channel); + CallOptions callOptions = stub.getCallOptions(); + assertFalse(callOptions.isWaitForReady()); + + stub = stub.withWaitForReady(); + callOptions = stub.getCallOptions(); + assertTrue(callOptions.isWaitForReady()); + } + + @Test + public void withExecutor() { + T stub = create(channel); + CallOptions callOptions = stub.getCallOptions(); + + assertNull(callOptions.getExecutor()); + + Executor executor = mock(Executor.class); + stub = stub.withExecutor(executor); + callOptions = stub.getCallOptions(); + + assertEquals(callOptions.getExecutor(), executor); + } +} diff --git a/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java b/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java index f976e7587f3..fad64947a58 100644 --- a/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java +++ b/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java @@ -158,7 +158,14 @@ io.grpc.testing.protobuf.SimpleResponse> getBidiStreamingRpcMethod() { * Creates a new async stub that supports all call types for the service */ public static SimpleServiceStub newStub(io.grpc.Channel channel) { - return new SimpleServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public SimpleServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new SimpleServiceStub(channel, callOptions); + } + }; + return SimpleServiceStub.newStub(factory, channel); } /** @@ -166,7 +173,14 @@ public static SimpleServiceStub newStub(io.grpc.Channel channel) { */ public static SimpleServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new SimpleServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public SimpleServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new SimpleServiceBlockingStub(channel, callOptions); + } + }; + return SimpleServiceBlockingStub.newStub(factory, channel); } /** @@ -174,7 +188,14 @@ public static SimpleServiceBlockingStub newBlockingStub( */ public static SimpleServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new SimpleServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public SimpleServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new SimpleServiceFutureStub(channel, callOptions); + } + }; + return SimpleServiceFutureStub.newStub(factory, channel); } /** @@ -263,19 +284,15 @@ public io.grpc.stub.StreamObserver bidiS * A simple service for test. * */ - public static final class SimpleServiceStub extends io.grpc.stub.AbstractStub { - private SimpleServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private SimpleServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class SimpleServiceStub extends io.grpc.stub.AbstractAsyncStub { + private SimpleServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected SimpleServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected SimpleServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new SimpleServiceStub(channel, callOptions); } @@ -329,19 +346,15 @@ public io.grpc.stub.StreamObserver bidiS * A simple service for test. * */ - public static final class SimpleServiceBlockingStub extends io.grpc.stub.AbstractStub { - private SimpleServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private SimpleServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class SimpleServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private SimpleServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected SimpleServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected SimpleServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new SimpleServiceBlockingStub(channel, callOptions); } @@ -372,19 +385,15 @@ public java.util.Iterator serverStreami * A simple service for test. * */ - public static final class SimpleServiceFutureStub extends io.grpc.stub.AbstractStub { - private SimpleServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private SimpleServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class SimpleServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private SimpleServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected SimpleServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected SimpleServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new SimpleServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java b/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java index 500543def62..59e43de5f93 100644 --- a/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java +++ b/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java @@ -72,7 +72,14 @@ com.github.udpa.udpa.data.orca.v1.OrcaLoadReport> getStreamCoreMetricsMethod() { * Creates a new async stub that supports all call types for the service */ public static OpenRcaServiceStub newStub(io.grpc.Channel channel) { - return new OpenRcaServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public OpenRcaServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new OpenRcaServiceStub(channel, callOptions); + } + }; + return OpenRcaServiceStub.newStub(factory, channel); } /** @@ -80,7 +87,14 @@ public static OpenRcaServiceStub newStub(io.grpc.Channel channel) { */ public static OpenRcaServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new OpenRcaServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public OpenRcaServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new OpenRcaServiceBlockingStub(channel, callOptions); + } + }; + return OpenRcaServiceBlockingStub.newStub(factory, channel); } /** @@ -88,7 +102,14 @@ public static OpenRcaServiceBlockingStub newBlockingStub( */ public static OpenRcaServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new OpenRcaServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public OpenRcaServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new OpenRcaServiceFutureStub(channel, callOptions); + } + }; + return OpenRcaServiceFutureStub.newStub(factory, channel); } /** @@ -137,19 +158,15 @@ public void streamCoreMetrics(com.github.udpa.udpa.service.orca.v1.OrcaLoadRepor * a new call to change backend reporting frequency. * */ - public static final class OpenRcaServiceStub extends io.grpc.stub.AbstractStub { - private OpenRcaServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private OpenRcaServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class OpenRcaServiceStub extends io.grpc.stub.AbstractAsyncStub { + private OpenRcaServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected OpenRcaServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected OpenRcaServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new OpenRcaServiceStub(channel, callOptions); } @@ -174,19 +191,15 @@ public void streamCoreMetrics(com.github.udpa.udpa.service.orca.v1.OrcaLoadRepor * a new call to change backend reporting frequency. * */ - public static final class OpenRcaServiceBlockingStub extends io.grpc.stub.AbstractStub { - private OpenRcaServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private OpenRcaServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class OpenRcaServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private OpenRcaServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected OpenRcaServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected OpenRcaServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new OpenRcaServiceBlockingStub(channel, callOptions); } @@ -211,19 +224,15 @@ public java.util.Iterator stre * a new call to change backend reporting frequency. * */ - public static final class OpenRcaServiceFutureStub extends io.grpc.stub.AbstractStub { - private OpenRcaServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private OpenRcaServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class OpenRcaServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private OpenRcaServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected OpenRcaServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected OpenRcaServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new OpenRcaServiceFutureStub(channel, callOptions); } } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java index 2726b2bf3ad..ce576e0ccb1 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java @@ -124,7 +124,14 @@ io.envoyproxy.envoy.api.v2.DiscoveryResponse> getFetchEndpointsMethod() { * Creates a new async stub that supports all call types for the service */ public static EndpointDiscoveryServiceStub newStub(io.grpc.Channel channel) { - return new EndpointDiscoveryServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public EndpointDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new EndpointDiscoveryServiceStub(channel, callOptions); + } + }; + return EndpointDiscoveryServiceStub.newStub(factory, channel); } /** @@ -132,7 +139,14 @@ public static EndpointDiscoveryServiceStub newStub(io.grpc.Channel channel) { */ public static EndpointDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new EndpointDiscoveryServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public EndpointDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new EndpointDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return EndpointDiscoveryServiceBlockingStub.newStub(factory, channel); } /** @@ -140,7 +154,14 @@ public static EndpointDiscoveryServiceBlockingStub newBlockingStub( */ public static EndpointDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new EndpointDiscoveryServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public EndpointDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new EndpointDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return EndpointDiscoveryServiceFutureStub.newStub(factory, channel); } /** @@ -201,19 +222,15 @@ public void fetchEndpoints(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, /** */ - public static final class EndpointDiscoveryServiceStub extends io.grpc.stub.AbstractStub { - private EndpointDiscoveryServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private EndpointDiscoveryServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class EndpointDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private EndpointDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected EndpointDiscoveryServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected EndpointDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new EndpointDiscoveryServiceStub(channel, callOptions); } @@ -248,19 +265,15 @@ public void fetchEndpoints(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, /** */ - public static final class EndpointDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { - private EndpointDiscoveryServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private EndpointDiscoveryServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class EndpointDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private EndpointDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected EndpointDiscoveryServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected EndpointDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new EndpointDiscoveryServiceBlockingStub(channel, callOptions); } @@ -274,19 +287,15 @@ public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchEndpoints(io.envoyproxy /** */ - public static final class EndpointDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { - private EndpointDiscoveryServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private EndpointDiscoveryServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class EndpointDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private EndpointDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected EndpointDiscoveryServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected EndpointDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new EndpointDiscoveryServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java index 65a23fff755..c9f8eb1ed02 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java @@ -101,7 +101,14 @@ io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse> getDeltaAggregatedResourcesMe * Creates a new async stub that supports all call types for the service */ public static AggregatedDiscoveryServiceStub newStub(io.grpc.Channel channel) { - return new AggregatedDiscoveryServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public AggregatedDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AggregatedDiscoveryServiceStub(channel, callOptions); + } + }; + return AggregatedDiscoveryServiceStub.newStub(factory, channel); } /** @@ -109,7 +116,14 @@ public static AggregatedDiscoveryServiceStub newStub(io.grpc.Channel channel) { */ public static AggregatedDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new AggregatedDiscoveryServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public AggregatedDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AggregatedDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return AggregatedDiscoveryServiceBlockingStub.newStub(factory, channel); } /** @@ -117,7 +131,14 @@ public static AggregatedDiscoveryServiceBlockingStub newBlockingStub( */ public static AggregatedDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new AggregatedDiscoveryServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public AggregatedDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new AggregatedDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return AggregatedDiscoveryServiceFutureStub.newStub(factory, channel); } /** @@ -179,19 +200,15 @@ public io.grpc.stub.StreamObserver */ - public static final class AggregatedDiscoveryServiceStub extends io.grpc.stub.AbstractStub { - private AggregatedDiscoveryServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private AggregatedDiscoveryServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class AggregatedDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private AggregatedDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AggregatedDiscoveryServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected AggregatedDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new AggregatedDiscoveryServiceStub(channel, callOptions); } @@ -225,19 +242,15 @@ public io.grpc.stub.StreamObserver */ - public static final class AggregatedDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { - private AggregatedDiscoveryServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private AggregatedDiscoveryServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class AggregatedDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private AggregatedDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AggregatedDiscoveryServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected AggregatedDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new AggregatedDiscoveryServiceBlockingStub(channel, callOptions); } } @@ -252,19 +265,15 @@ protected AggregatedDiscoveryServiceBlockingStub build(io.grpc.Channel channel, * the multiplexed singleton APIs at the Envoy instance and management server. * */ - public static final class AggregatedDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { - private AggregatedDiscoveryServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private AggregatedDiscoveryServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class AggregatedDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private AggregatedDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AggregatedDiscoveryServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected AggregatedDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new AggregatedDiscoveryServiceFutureStub(channel, callOptions); } } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java index f00828aa3f5..66271d2e60c 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java @@ -62,7 +62,14 @@ io.envoyproxy.envoy.service.load_stats.v2.LoadStatsResponse> getStreamLoadStatsM * Creates a new async stub that supports all call types for the service */ public static LoadReportingServiceStub newStub(io.grpc.Channel channel) { - return new LoadReportingServiceStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoadReportingServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoadReportingServiceStub(channel, callOptions); + } + }; + return LoadReportingServiceStub.newStub(factory, channel); } /** @@ -70,7 +77,14 @@ public static LoadReportingServiceStub newStub(io.grpc.Channel channel) { */ public static LoadReportingServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - return new LoadReportingServiceBlockingStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoadReportingServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoadReportingServiceBlockingStub(channel, callOptions); + } + }; + return LoadReportingServiceBlockingStub.newStub(factory, channel); } /** @@ -78,7 +92,14 @@ public static LoadReportingServiceBlockingStub newBlockingStub( */ public static LoadReportingServiceFutureStub newFutureStub( io.grpc.Channel channel) { - return new LoadReportingServiceFutureStub(channel); + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public LoadReportingServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new LoadReportingServiceFutureStub(channel, callOptions); + } + }; + return LoadReportingServiceFutureStub.newStub(factory, channel); } /** @@ -136,19 +157,15 @@ public io.grpc.stub.StreamObserver { - private LoadReportingServiceStub(io.grpc.Channel channel) { - super(channel); - } - - private LoadReportingServiceStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class LoadReportingServiceStub extends io.grpc.stub.AbstractAsyncStub { + private LoadReportingServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadReportingServiceStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected LoadReportingServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new LoadReportingServiceStub(channel, callOptions); } @@ -192,38 +209,30 @@ public io.grpc.stub.StreamObserver { - private LoadReportingServiceBlockingStub(io.grpc.Channel channel) { - super(channel); - } - - private LoadReportingServiceBlockingStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class LoadReportingServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private LoadReportingServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadReportingServiceBlockingStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected LoadReportingServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new LoadReportingServiceBlockingStub(channel, callOptions); } } /** */ - public static final class LoadReportingServiceFutureStub extends io.grpc.stub.AbstractStub { - private LoadReportingServiceFutureStub(io.grpc.Channel channel) { - super(channel); - } - - private LoadReportingServiceFutureStub(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + public static final class LoadReportingServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private LoadReportingServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadReportingServiceFutureStub build(io.grpc.Channel channel, - io.grpc.CallOptions callOptions) { + protected LoadReportingServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { return new LoadReportingServiceFutureStub(channel, callOptions); } } From fe46edacea7436e99fef15e5bb4b7850535999a9 Mon Sep 17 00:00:00 2001 From: Ran Date: Thu, 17 Oct 2019 14:49:53 -0700 Subject: [PATCH 105/131] stub: ignore unary response msg if status is not OK (#6288) * stub: ignore unary response msg if status is not OK * stub: throw if no msg with OK status * address the comment, improve tests. * fix error message * fix error message * improve naming of the tests * call onCompleted on success unary flow * fix test * handle errors for delayed unary message sending * clean up the onCompleted/onError logic * use hasMessageThat to produce better error message when fail --- .../main/java/io/grpc/stub/ClientCalls.java | 29 ++++- .../java/io/grpc/stub/ClientCallsTest.java | 117 ++++++++++++++++++ 2 files changed, 144 insertions(+), 2 deletions(-) diff --git a/stub/src/main/java/io/grpc/stub/ClientCalls.java b/stub/src/main/java/io/grpc/stub/ClientCalls.java index 4c78b1b6520..82793cd3d89 100644 --- a/stub/src/main/java/io/grpc/stub/ClientCalls.java +++ b/stub/src/main/java/io/grpc/stub/ClientCalls.java @@ -401,6 +401,7 @@ private static final class StreamObserverToCallListenerAdapter private final CallToStreamObserverAdapter adapter; private final boolean streamingResponse; private boolean firstResponseReceived; + private RespT unaryMessage; // Non private to avoid synthetic class StreamObserverToCallListenerAdapter( @@ -431,7 +432,13 @@ public void onMessage(RespT message) { .asRuntimeException(); } firstResponseReceived = true; - observer.onNext(message); + + if (streamingResponse) { + observer.onNext(message); + } else { + // will send message in onClose() for unary calls. + unaryMessage = message; + } if (streamingResponse && adapter.autoFlowControlEnabled) { // Request delivery of the next inbound message. @@ -441,10 +448,28 @@ public void onMessage(RespT message) { @Override public void onClose(Status status, Metadata trailers) { + Throwable error = null; if (status.isOk()) { + if (!streamingResponse) { + if (unaryMessage != null) { + try { + observer.onNext(unaryMessage); + } catch (Throwable t) { + error = t; + } + } else { + error = Status.INTERNAL.withDescription("Response message is null for unary call") + .asRuntimeException(); + } + } + } else { + error = status.asRuntimeException(trailers); + } + + if (error == null) { observer.onCompleted(); } else { - observer.onError(status.asRuntimeException(trailers)); + observer.onError(error); } } diff --git a/stub/src/test/java/io/grpc/stub/ClientCallsTest.java b/stub/src/test/java/io/grpc/stub/ClientCallsTest.java index a6364877063..9e70fb17658 100644 --- a/stub/src/test/java/io/grpc/stub/ClientCallsTest.java +++ b/stub/src/test/java/io/grpc/stub/ClientCallsTest.java @@ -99,6 +99,123 @@ public void tearDown() { } } + @Test + public void unaryAsyncCallStatusIsOkWithMessageSuccess() throws Exception { + Integer req = 2; + final String resp = "bar"; + final Status status = Status.OK; + final Metadata trailers = new Metadata(); + final List actualResponse = new ArrayList<>(); + final List completed = new ArrayList<>(); + + NoopClientCall call = new NoopClientCall() { + @Override + public void start(ClientCall.Listener listener, Metadata headers) { + listener.onMessage(resp); + listener.onClose(status, trailers); + } + }; + + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(String value) { + actualResponse.add(value); + } + + @Override + public void onError(Throwable t) { + fail("Should not reach here"); + } + + @Override + public void onCompleted() { + completed.add(true); + } + }; + + ClientCalls.asyncUnaryCall(call, req, responseObserver); + assertThat(actualResponse.size()).isEqualTo(1); + assertEquals(resp, actualResponse.get(0)); + assertThat(completed.size()).isEqualTo(1); + assertThat(completed.get(0)).isTrue(); + } + + @Test + public void unaryAsyncCallStatusIsOkWithNullMessageGetError() throws Exception { + Integer req = 2; + final Status status = Status.OK; + final Metadata trailers = new Metadata(); + final List expected = new ArrayList<>(); + + NoopClientCall call = new NoopClientCall() { + @Override + public void start(ClientCall.Listener listener, Metadata headers) { + listener.onMessage(null); + listener.onClose(status, trailers); + } + }; + + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(String value) { + fail("Should not reach here"); + } + + @Override + public void onError(Throwable t) { + expected.add(t); + } + + @Override + public void onCompleted() { + fail("Should not reach here"); + } + }; + + ClientCalls.asyncUnaryCall(call, req, responseObserver); + assertThat(expected.size()).isEqualTo(1); + assertThat(expected.get(0)).hasMessageThat() + .isEqualTo("INTERNAL: Response message is null for unary call"); + } + + @Test + public void unaryAsyncCallStatusIsNotOkWithMessageDoNotSendMessage() throws Exception { + Integer req = 2; + final Status status = Status.INTERNAL.withDescription("Unique status"); + final String resp = "bar"; + final Metadata trailers = new Metadata(); + final List expected = new ArrayList<>(); + + NoopClientCall call = new NoopClientCall() { + @Override + public void start(io.grpc.ClientCall.Listener listener, Metadata headers) { + listener.onMessage(resp); + listener.onClose(status, trailers); + } + }; + + StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(String value) { + fail("Should not reach here"); + } + + @Override + public void onError(Throwable t) { + expected.add(t); + } + + @Override + public void onCompleted() { + fail("Should not reach here"); + } + }; + + ClientCalls.asyncUnaryCall(call, req, responseObserver); + assertThat(expected.size()).isEqualTo(1); + assertThat(expected.get(0)).hasMessageThat().isEqualTo("INTERNAL: Unique status"); + } + @Test public void unaryBlockingCallSuccess() throws Exception { Integer req = 2; From 1dd72ab043b7596e9ecff59fb3a666e4480e738e Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Thu, 17 Oct 2019 17:23:40 -0700 Subject: [PATCH 106/131] xds: update envoy proto version to f709434b37e9ff74666d5b854aa11fb2f1ec37f3 (#6291) --- xds/third_party/envoy/NOTICE | 2 +- xds/third_party/envoy/import.sh | 2 +- .../main/proto/envoy/api/v2/auth/cert.proto | 59 +++--- .../proto/envoy/api/v2/core/address.proto | 29 +-- .../main/proto/envoy/api/v2/core/base.proto | 132 +++++++------- .../envoy/api/v2/core/config_source.proto | 41 ++++- .../envoy/api/v2/core/grpc_service.proto | 33 ++-- .../envoy/api/v2/core/health_check.proto | 169 ++++++++---------- .../proto/envoy/api/v2/core/http_uri.proto | 17 +- .../main/proto/envoy/api/v2/discovery.proto | 12 +- .../src/main/proto/envoy/api/v2/eds.proto | 57 +++--- .../envoy/api/v2/endpoint/endpoint.proto | 27 ++- .../envoy/api/v2/endpoint/load_report.proto | 1 - .../envoy/service/discovery/v2/ads.proto | 19 +- .../envoy/service/load_stats/v2/lrs.proto | 1 - .../src/main/proto/envoy/type/percent.proto | 13 +- .../src/main/proto/envoy/type/range.proto | 5 - 17 files changed, 312 insertions(+), 307 deletions(-) diff --git a/xds/third_party/envoy/NOTICE b/xds/third_party/envoy/NOTICE index da867a29ec8..9a9b287cbe8 100644 --- a/xds/third_party/envoy/NOTICE +++ b/xds/third_party/envoy/NOTICE @@ -1,4 +1,4 @@ Envoy -Copyright 2016-2018 Envoy Project Authors +Copyright 2016-2019 Envoy Project Authors Licensed under Apache License 2.0. See LICENSE for terms. diff --git a/xds/third_party/envoy/import.sh b/xds/third_party/envoy/import.sh index c347a0ab73a..0a4b44738b1 100755 --- a/xds/third_party/envoy/import.sh +++ b/xds/third_party/envoy/import.sh @@ -18,7 +18,7 @@ set -e BRANCH=master # import VERSION from one of the google internal CLs -VERSION=6ff0bce8ff417a252cde4d04dfb9cba2bab463d8 +VERSION=f709434b37e9ff74666d5b854aa11fb2f1ec37f3 GIT_REPO="https://github.com/envoyproxy/envoy.git" GIT_BASE_DIR=envoy SOURCE_PROTO_BASE_DIR=envoy/api diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto index 30db22c6d7a..ebf199a4743 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/auth/cert.proto @@ -5,7 +5,6 @@ package envoy.api.v2.auth; option java_outer_classname = "CertProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2.auth"; -option go_package = "auth"; import "envoy/api/v2/core/base.proto"; import "envoy/api/v2/core/config_source.proto"; @@ -15,9 +14,6 @@ import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Common TLS configuration] @@ -40,11 +36,11 @@ message TlsParameters { } // Minimum TLS protocol version. By default, it's ``TLSv1_0``. - TlsProtocol tls_minimum_protocol_version = 1 [(validate.rules).enum.defined_only = true]; + TlsProtocol tls_minimum_protocol_version = 1 [(validate.rules).enum = {defined_only: true}]; // Maximum TLS protocol version. By default, it's ``TLSv1_3`` for servers in non-FIPS builds, and // ``TLSv1_2`` for clients and for servers using :ref:`BoringSSL FIPS `. - TlsProtocol tls_maximum_protocol_version = 2 [(validate.rules).enum.defined_only = true]; + TlsProtocol tls_maximum_protocol_version = 2 [(validate.rules).enum = {defined_only: true}]; // If specified, the TLS listener will only support the specified `cipher list // `_ @@ -110,7 +106,7 @@ message TlsParameters { message PrivateKeyProvider { // Private key method provider name. The name must match a // supported private key method provider type. - string provider_name = 1 [(validate.rules).string.min_bytes = 1]; + string provider_name = 1 [(validate.rules).string = {min_bytes: 1}]; // Private key method provider specific configuration. oneof config_type { @@ -171,7 +167,7 @@ message TlsSessionTicketKeys { // * Keep the session ticket keys at least as secure as your TLS certificate private keys // * Rotate session ticket keys at least daily, and preferably hourly // * Always generate keys using a cryptographically-secure random data source - repeated core.DataSource keys = 1 [(validate.rules).repeated .min_items = 1]; + repeated core.DataSource keys = 1 [(validate.rules).repeated = {min_items: 1}]; } message CertificateValidationContext { @@ -205,9 +201,9 @@ message CertificateValidationContext { // // .. code-block:: bash // - // $ openssl x509 -in path/to/client.crt -noout -pubkey \ - // | openssl pkey -pubin -outform DER \ - // | openssl dgst -sha256 -binary \ + // $ openssl x509 -in path/to/client.crt -noout -pubkey + // | openssl pkey -pubin -outform DER + // | openssl dgst -sha256 -binary // | openssl enc -base64 // NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= // @@ -227,7 +223,7 @@ message CertificateValidationContext { // because SPKI is tied to a private key, so it doesn't change when the certificate // is renewed using the same private key. repeated string verify_certificate_spki = 3 - [(validate.rules).repeated .items.string = {min_bytes: 44, max_bytes: 44}]; + [(validate.rules).repeated = {items {string {min_bytes: 44 max_bytes: 44}}}]; // An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that // the SHA-256 of the DER-encoded presented certificate matches one of the specified values. @@ -256,7 +252,7 @@ message CertificateValidationContext { // ` are specified, // a hash matching value from either of the lists will result in the certificate being accepted. repeated string verify_certificate_hash = 2 - [(validate.rules).repeated .items.string = {min_bytes: 64, max_bytes: 95}]; + [(validate.rules).repeated = {items {string {min_bytes: 64 max_bytes: 95}}}]; // An optional list of Subject Alternative Names. If specified, Envoy will verify that the // Subject Alternative Name of the presented certificate matches one of the specified values. @@ -287,6 +283,18 @@ message CertificateValidationContext { // TLS context shared by both client and server TLS contexts. message CommonTlsContext { + message CombinedCertificateValidationContext { + // How to validate peer certificates. + CertificateValidationContext default_validation_context = 1 + [(validate.rules).message = {required: true}]; + + // Config for fetching validation context via SDS API. + SdsSecretConfig validation_context_sds_secret_config = 2 + [(validate.rules).message = {required: true}]; + } + + reserved 5; + // TLS protocol versions, cipher suites etc. TlsParameters tls_params = 1; @@ -300,17 +308,7 @@ message CommonTlsContext { // Configs for fetching TLS certificates via SDS API. repeated SdsSecretConfig tls_certificate_sds_secret_configs = 6 - [(validate.rules).repeated .max_items = 1]; - - message CombinedCertificateValidationContext { - // How to validate peer certificates. - CertificateValidationContext default_validation_context = 1 - [(validate.rules).message.required = true]; - - // Config for fetching validation context via SDS API. - SdsSecretConfig validation_context_sds_secret_config = 2 - [(validate.rules).message.required = true]; - }; + [(validate.rules).repeated = {max_items: 1}]; oneof validation_context_type { // How to validate peer certificates. @@ -340,8 +338,6 @@ message CommonTlsContext { // // There is no default for this parameter. If empty, Envoy will not expose ALPN. repeated string alpn_protocols = 4; - - reserved 5; } message UpstreamTlsContext { @@ -349,7 +345,7 @@ message UpstreamTlsContext { CommonTlsContext common_tls_context = 1; // SNI string to use when creating TLS backend connections. - string sni = 2 [(validate.rules).string.max_bytes = 255]; + string sni = 2 [(validate.rules).string = {max_bytes: 255}]; // If true, server-initiated TLS renegotiation will be allowed. // @@ -386,22 +382,25 @@ message DownstreamTlsContext { } } -// [#proto-status: experimental] message SdsSecretConfig { // Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. // When both name and config are specified, then secret can be fetched and/or reloaded via SDS. - // When only name is specified, then secret will be loaded from static resources [V2-API-DIFF]. + // When only name is specified, then secret will be loaded from static + // resources. string name = 1; + core.ConfigSource sds_config = 2; } -// [#proto-status: experimental] message Secret { // Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. string name = 1; + oneof type { TlsCertificate tls_certificate = 2; + TlsSessionTicketKeys session_ticket_keys = 3; + CertificateValidationContext validation_context = 4; } } diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/address.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/address.proto index 88689e2648c..89fd0adb1eb 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/address.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/address.proto @@ -11,9 +11,6 @@ import "envoy/api/v2/core/base.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Network addresses] @@ -22,17 +19,19 @@ message Pipe { // abstract namespace. The starting '@' is replaced by a null byte by Envoy. // Paths starting with '@' will result in an error in environments other than // Linux. - string path = 1 [(validate.rules).string.min_bytes = 1]; + string path = 1 [(validate.rules).string = {min_bytes: 1}]; } message SocketAddress { enum Protocol { - option (gogoproto.goproto_enum_prefix) = false; TCP = 0; + // [#not-implemented-hide:] UDP = 1; } - Protocol protocol = 1 [(validate.rules).enum.defined_only = true]; + + Protocol protocol = 1 [(validate.rules).enum = {defined_only: true}]; + // The address for this socket. :ref:`Listeners ` will bind // to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` // to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: @@ -44,15 +43,19 @@ message SocketAddress { // address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS // (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized // via :ref:`resolver_name `. - string address = 2 [(validate.rules).string.min_bytes = 1]; + string address = 2 [(validate.rules).string = {min_bytes: 1}]; + oneof port_specifier { option (validate.required) = true; - uint32 port_value = 3 [(validate.rules).uint32.lte = 65535]; + + uint32 port_value = 3 [(validate.rules).uint32 = {lte: 65535}]; + // This is only valid if :ref:`resolver_name // ` is specified below and the // named resolver is capable of named port resolution. string named_port = 4; } + // The name of the custom resolver. This must have been registered with Envoy. If // this is empty, a context dependent default applies. If the address is a concrete // IP address, no resolution will occur. If address is a hostname this @@ -72,10 +75,12 @@ message TcpKeepalive { // the connection is dead. Default is to use the OS level configuration (unless // overridden, Linux defaults to 9.) google.protobuf.UInt32Value keepalive_probes = 1; + // The number of seconds a connection needs to be idle before keep-alive probes // start being sent. Default is to use the OS level configuration (unless // overridden, Linux defaults to 7200s (ie 2 hours.) google.protobuf.UInt32Value keepalive_time = 2; + // The number of seconds between keep-alive probes. Default is to use the OS // level configuration (unless overridden, Linux defaults to 75s.) google.protobuf.UInt32Value keepalive_interval = 3; @@ -83,7 +88,7 @@ message TcpKeepalive { message BindConfig { // The address to bind to when creating a socket. - SocketAddress source_address = 1 [(validate.rules).message.required = true]; + SocketAddress source_address = 1 [(validate.rules).message = {required: true}]; // Whether to set the *IP_FREEBIND* option when creating the socket. When this // flag is set to true, allows the :ref:`source_address @@ -107,6 +112,7 @@ message Address { option (validate.required) = true; SocketAddress socket_address = 1; + Pipe pipe = 2; } } @@ -115,7 +121,8 @@ message Address { // the subnet mask for a `CIDR `_ range. message CidrRange { // IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. - string address_prefix = 1 [(validate.rules).string.min_bytes = 1]; + string address_prefix = 1 [(validate.rules).string = {min_bytes: 1}]; + // Length of prefix, e.g. 0, 32. - google.protobuf.UInt32Value prefix_len = 2 [(validate.rules).uint32.lte = 128]; + google.protobuf.UInt32Value prefix_len = 2 [(validate.rules).uint32 = {lte: 128}]; } diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/base.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/base.proto index 2553fe04de2..eca00760575 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/base.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/base.proto @@ -5,23 +5,55 @@ package envoy.api.v2.core; option java_outer_classname = "BaseProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2.core"; -option go_package = "core"; import "envoy/api/v2/core/http_uri.proto"; +import "envoy/type/percent.proto"; import "google/protobuf/any.proto"; import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; -import "envoy/type/percent.proto"; +// [#protodoc-title: Common types] -option (gogoproto.equal_all) = true; -option (gogoproto.stable_marshaler_all) = true; +// Envoy supports :ref:`upstream priority routing +// ` both at the route and the virtual +// cluster level. The current priority implementation uses different connection +// pool and circuit breaking settings for each priority level. This means that +// even for HTTP/2 requests, two physical connections will be used to an +// upstream host. In the future Envoy will likely support true HTTP/2 priority +// over a single upstream connection. +enum RoutingPriority { + DEFAULT = 0; + HIGH = 1; +} -// [#protodoc-title: Common types] +// HTTP request method. +enum RequestMethod { + METHOD_UNSPECIFIED = 0; + GET = 1; + HEAD = 2; + POST = 3; + PUT = 4; + DELETE = 5; + CONNECT = 6; + OPTIONS = 7; + TRACE = 8; + PATCH = 9; +} + +// Identifies the direction of the traffic relative to the local Envoy. +enum TrafficDirection { + // Default option is unspecified. + UNSPECIFIED = 0; + + // The transport is used for incoming traffic. + INBOUND = 1; + + // The transport is used for outgoing traffic. + OUTBOUND = 2; +} // Identifies location of where either Envoy runs or where upstream hosts run. message Locality { @@ -115,53 +147,26 @@ message RuntimeUInt32 { uint32 default_value = 2; // Runtime key to get value for comparison. This value is used if defined. - string runtime_key = 3 [(validate.rules).string.min_bytes = 1]; -} - -// Envoy supports :ref:`upstream priority routing -// ` both at the route and the virtual -// cluster level. The current priority implementation uses different connection -// pool and circuit breaking settings for each priority level. This means that -// even for HTTP/2 requests, two physical connections will be used to an -// upstream host. In the future Envoy will likely support true HTTP/2 priority -// over a single upstream connection. -enum RoutingPriority { - DEFAULT = 0; - HIGH = 1; -} - -// HTTP request method. -enum RequestMethod { - option (gogoproto.goproto_enum_prefix) = false; - METHOD_UNSPECIFIED = 0; - GET = 1; - HEAD = 2; - POST = 3; - PUT = 4; - DELETE = 5; - CONNECT = 6; - OPTIONS = 7; - TRACE = 8; - PATCH = 9; + string runtime_key = 3 [(validate.rules).string = {min_bytes: 1}]; } // Header name/value pair. message HeaderValue { // Header name. - string key = 1 [(validate.rules).string = {min_bytes: 1, max_bytes: 16384}]; + string key = 1 [(validate.rules).string = {min_bytes: 1 max_bytes: 16384}]; // Header value. // // The same :ref:`format specifier ` as used for // :ref:`HTTP access logging ` applies here, however // unknown header values are replaced with the empty string instead of `-`. - string value = 2 [(validate.rules).string.max_bytes = 16384]; + string value = 2 [(validate.rules).string = {max_bytes: 16384}]; } // Header name/value pair plus option to control append behavior. message HeaderValueOption { // Header name/value pair that this option applies to. - HeaderValue header = 1 [(validate.rules).message.required = true]; + HeaderValue header = 1 [(validate.rules).message = {required: true}]; // Should the value be appended? If true (default), the value is appended to // existing values. @@ -179,23 +184,23 @@ message DataSource { option (validate.required) = true; // Local filesystem data source. - string filename = 1 [(validate.rules).string.min_bytes = 1]; + string filename = 1 [(validate.rules).string = {min_bytes: 1}]; // Bytes inlined in the configuration. - bytes inline_bytes = 2 [(validate.rules).bytes.min_len = 1]; + bytes inline_bytes = 2 [(validate.rules).bytes = {min_len: 1}]; // String inlined in the configuration. - string inline_string = 3 [(validate.rules).string.min_bytes = 1]; + string inline_string = 3 [(validate.rules).string = {min_bytes: 1}]; } } // The message specifies how to fetch data from remote and how to verify it. message RemoteDataSource { // The HTTP URI to fetch the remote data. - HttpUri http_uri = 1 [(validate.rules).message.required = true]; + HttpUri http_uri = 1 [(validate.rules).message = {required: true}]; // SHA256 string for verifying data. - string sha256 = 2 [(validate.rules).string.min_bytes = 1]; + string sha256 = 2 [(validate.rules).string = {min_bytes: 1}]; } // Async data source which support async data fetch. @@ -218,7 +223,7 @@ message AsyncDataSource { message TransportSocket { // The name of the transport socket to instantiate. The name must match a supported transport // socket implementation. - string name = 1 [(validate.rules).string.min_bytes = 1]; + string name = 1 [(validate.rules).string = {min_bytes: 1}]; // Implementation specific configuration which depends on the implementation being instantiated. // See the supported transport socket implementations for further documentation. @@ -232,40 +237,47 @@ message TransportSocket { // Generic socket option message. This would be used to set socket options that // might not exist in upstream kernels or precompiled Envoy binaries. message SocketOption { + enum SocketState { + // Socket options are applied after socket creation but before binding the socket to a port + STATE_PREBIND = 0; + + // Socket options are applied after binding the socket to a port but before calling listen() + STATE_BOUND = 1; + + // Socket options are applied after calling listen() + STATE_LISTENING = 2; + } + // An optional name to give this socket option for debugging, etc. // Uniqueness is not required and no special meaning is assumed. string description = 1; + // Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP int64 level = 2; + // The numeric name as passed to setsockopt int64 name = 3; + oneof value { option (validate.required) = true; // Because many sockopts take an int value. int64 int_value = 4; + // Otherwise it's a byte buffer. bytes buf_value = 5; } - enum SocketState { - option (gogoproto.goproto_enum_prefix) = false; - // Socket options are applied after socket creation but before binding the socket to a port - STATE_PREBIND = 0; - // Socket options are applied after binding the socket to a port but before calling listen() - STATE_BOUND = 1; - // Socket options are applied after calling listen() - STATE_LISTENING = 2; - } + // The state in which the option will be applied. When used in BindConfig // STATE_PREBIND is currently the only valid value. - SocketState state = 6 [(validate.rules).enum.defined_only = true]; + SocketState state = 6 [(validate.rules).enum = {defined_only: true}]; } // Runtime derived FractionalPercent with defaults for when the numerator or denominator is not // specified via a runtime key. message RuntimeFractionalPercent { // Default value if the runtime value's for the numerator/denominator keys are not available. - envoy.type.FractionalPercent default_value = 1 [(validate.rules).message.required = true]; + type.FractionalPercent default_value = 1 [(validate.rules).message = {required: true}]; // Runtime key for a YAML representation of a FractionalPercent. string runtime_key = 2; @@ -278,15 +290,3 @@ message ControlPlane { // the Envoy is connected to. string identifier = 1; } - -// Identifies the direction of the traffic relative to the local Envoy. -enum TrafficDirection { - // Default option is unspecified. - UNSPECIFIED = 0; - - // The transport is used for incoming traffic. - INBOUND = 1; - - // The transport is used for outgoing traffic. - OUTBOUND = 2; -} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/config_source.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/config_source.proto index 9b77f12f5be..240d37b81ee 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/config_source.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/config_source.proto @@ -12,9 +12,6 @@ import "google/protobuf/duration.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Configuration sources] @@ -26,12 +23,15 @@ message ApiConfigSource { // Ideally this would be 'reserved 0' but one can't reserve the default // value. Instead we throw an exception if this is ever used. UNSUPPORTED_REST_LEGACY = 0 [deprecated = true]; + // REST-JSON v2 API. The `canonical JSON encoding // `_ for // the v2 protos is used. REST = 1; + // gRPC v2 API. GRPC = 2; + // Using the delta xDS gRPC service, i.e. DeltaDiscovery{Request,Response} // rather than Discovery{Request,Response}. Rather than sending Envoy the entire state // with every update, the xDS server only sends what has changed since the last update. @@ -40,7 +40,9 @@ message ApiConfigSource { // Do not use for other xDSes. TODO(fredlas) update/remove this warning when appropriate. DELTA_GRPC = 3; } - ApiType api_type = 1 [(validate.rules).enum.defined_only = true]; + + ApiType api_type = 1 [(validate.rules).enum = {defined_only: true}]; + // Cluster names should be used only with REST. If > 1 // cluster is defined, clusters will be cycled through if any kind of failure // occurs. @@ -56,11 +58,10 @@ message ApiConfigSource { repeated GrpcService grpc_services = 4; // For REST APIs, the delay between successive polls. - google.protobuf.Duration refresh_delay = 3 [(gogoproto.stdduration) = true]; + google.protobuf.Duration refresh_delay = 3; // For REST APIs, the request timeout. If not set, a default value of 1s will be used. - google.protobuf.Duration request_timeout = 5 - [(validate.rules).duration.gt.seconds = 0, (gogoproto.stdduration) = true]; + google.protobuf.Duration request_timeout = 5 [(validate.rules).duration = {gt {}}]; // For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be // rate limited. @@ -76,6 +77,13 @@ message ApiConfigSource { message AggregatedConfigSource { } +// [#not-implemented-hide:] +// Self-referencing config source options. This is currently empty, but when +// set in :ref:`ConfigSource ` can be used to +// specify that other data can be obtained from the same server. +message SelfConfigSource { +} + // Rate Limit settings to be applied for discovery requests made by Envoy. message RateLimitSettings { // Maximum number of tokens to be used for rate limiting discovery request calls. If not set, a @@ -84,7 +92,7 @@ message RateLimitSettings { // Rate at which tokens will be filled per second. If not set, a default fill rate of 10 tokens // per second will be used. - google.protobuf.DoubleValue fill_rate = 2 [(validate.rules).double.gt = 0.0]; + google.protobuf.DoubleValue fill_rate = 2 [(validate.rules).double = {gt: 0.0}]; } // Configuration for :ref:`listeners `, :ref:`clusters @@ -93,9 +101,11 @@ message RateLimitSettings { // ` etc. may either be sourced from the // filesystem or from an xDS API source. Filesystem configs are watched with // inotify for updates. +// [#comment:next free field: 6] message ConfigSource { oneof config_source_specifier { option (validate.required) = true; + // Path on the filesystem to source and watch for configuration updates. // // .. note:: @@ -108,11 +118,26 @@ message ConfigSource { // are atomic. The same method of swapping files as is demonstrated in the // :ref:`runtime documentation ` can be used here also. string path = 1; + // API configuration source. ApiConfigSource api_config_source = 2; + // When set, ADS will be used to fetch resources. The ADS API configuration // source in the bootstrap configuration is used. AggregatedConfigSource ads = 3; + + // [#not-implemented-hide:] + // When set, the client will access the resources from the same server it got the + // ConfigSource from, although not necessarily from the same stream. This is similar to the + // :ref:`ads` field, except that the client may use a + // different stream to the same server. As a result, this field can be used for things + // like LRS that cannot be sent on an ADS stream. It can also be used to link from (e.g.) + // LDS to RDS on the same server without requiring the management server to know its name + // or required credentials. + // [#next-major-version: In xDS v3, consider replacing the ads field with this one, since + // this field can implicitly mean to use the same stream in the case where the ConfigSource + // is provided via ADS and the specified data can also be obtained via ADS.] + SelfConfigSource self = 5; } // When this timeout is specified, Envoy will wait no longer than the specified time for first diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/grpc_service.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/grpc_service.proto index 404791e1b3a..cbe6c8296e1 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/grpc_service.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/grpc_service.proto @@ -10,13 +10,10 @@ import "envoy/api/v2/core/base.proto"; import "google/protobuf/any.proto"; import "google/protobuf/duration.proto"; -import "google/protobuf/struct.proto"; import "google/protobuf/empty.proto"; +import "google/protobuf/struct.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: gRPC services] @@ -27,16 +24,10 @@ message GrpcService { // The name of the upstream gRPC cluster. SSL credentials will be supplied // in the :ref:`Cluster ` :ref:`tls_context // `. - string cluster_name = 1 [(validate.rules).string.min_bytes = 1]; + string cluster_name = 1 [(validate.rules).string = {min_bytes: 1}]; } - // [#proto-status: draft] message GoogleGrpc { - // The target URI when using the `Google C++ gRPC client - // `_. SSL credentials will be supplied in - // :ref:`channel_credentials `. - string target_uri = 1 [(validate.rules).string.min_bytes = 1]; - // See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. message SslCredentials { // PEM encoded server root certificates. @@ -59,6 +50,7 @@ message GrpcService { message ChannelCredentials { oneof credential_specifier { option (validate.required) = true; + SslCredentials ssl_credentials = 1; // https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 @@ -68,21 +60,22 @@ message GrpcService { } } - ChannelCredentials channel_credentials = 2; - message CallCredentials { message ServiceAccountJWTAccessCredentials { string json_key = 1; + uint64 token_lifetime_seconds = 2; } message GoogleIAMCredentials { string authorization_token = 1; + string authority_selector = 2; } message MetadataCredentialsFromPlugin { string name = 1; + oneof config_type { google.protobuf.Struct config = 2; @@ -120,6 +113,13 @@ message GrpcService { } } + // The target URI when using the `Google C++ gRPC client + // `_. SSL credentials will be supplied in + // :ref:`channel_credentials `. + string target_uri = 1 [(validate.rules).string = {min_bytes: 1}]; + + ChannelCredentials channel_credentials = 2; + // A set of call credentials that can be composed with `channel credentials // `_. repeated CallCredentials call_credentials = 3; @@ -133,7 +133,7 @@ message GrpcService { // // streams_total, Counter, Total number of streams opened // streams_closed_, Counter, Total streams closed with - string stat_prefix = 4 [(validate.rules).string.min_bytes = 1]; + string stat_prefix = 4 [(validate.rules).string = {min_bytes: 1}]; // The name of the Google gRPC credentials factory to use. This must have been registered with // Envoy. If this is empty, a default credentials factory will be used that sets up channel @@ -145,6 +145,8 @@ message GrpcService { google.protobuf.Struct config = 6; } + reserved 4; + oneof target_specifier { option (validate.required) = true; @@ -163,9 +165,6 @@ message GrpcService { // request. google.protobuf.Duration timeout = 3; - // Field 4 reserved due to moving credentials inside the GoogleGrpc message - reserved 4; - // Additional metadata to include in streams initiated to the GrpcService. // This can be used for scenarios in which additional ad hoc authorization // headers (e.g. `x-foo-bar: baz-key`) are to be injected. diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/health_check.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/health_check.proto index edbcef7b52d..078a5a4beef 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/health_check.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/health_check.proto @@ -15,75 +15,46 @@ import "google/protobuf/struct.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Health check] // * Health checking :ref:`architecture overview `. // * If health checking is configured for a cluster, additional statistics are emitted. They are // documented :ref:`here `. -message HealthCheck { - // The time to wait for a health check response. If the timeout is reached the - // health check attempt will be considered a failure. - google.protobuf.Duration timeout = 1 [ - (validate.rules).duration = { - required: true, - gt: {seconds: 0} - }, - (gogoproto.stdduration) = true - ]; - - // The interval between health checks. - google.protobuf.Duration interval = 2 [ - (validate.rules).duration = { - required: true, - gt: {seconds: 0} - }, - (gogoproto.stdduration) = true - ]; - - // An optional jitter amount in milliseconds. If specified, Envoy will start health - // checking after for a random time in ms between 0 and initial_jitter. This only - // applies to the first health check. - google.protobuf.Duration initial_jitter = 20; - - // An optional jitter amount in milliseconds. If specified, during every - // interval Envoy will add interval_jitter to the wait time. - google.protobuf.Duration interval_jitter = 3; +// Endpoint health status. +enum HealthStatus { + // The health status is not known. This is interpreted by Envoy as *HEALTHY*. + UNKNOWN = 0; - // An optional jitter amount as a percentage of interval_ms. If specified, - // during every interval Envoy will add interval_ms * - // interval_jitter_percent / 100 to the wait time. - // - // If interval_jitter_ms and interval_jitter_percent are both set, both of - // them will be used to increase the wait time. - uint32 interval_jitter_percent = 18; + // Healthy. + HEALTHY = 1; - // The number of unhealthy health checks required before a host is marked - // unhealthy. Note that for *http* health checking if a host responds with 503 - // this threshold is ignored and the host is considered unhealthy immediately. - google.protobuf.UInt32Value unhealthy_threshold = 4; + // Unhealthy. + UNHEALTHY = 2; - // The number of healthy health checks required before a host is marked - // healthy. Note that during startup, only a single successful health check is - // required to mark a host healthy. - google.protobuf.UInt32Value healthy_threshold = 5; + // Connection draining in progress. E.g., + // ``_ + // or + // ``_. + // This is interpreted by Envoy as *UNHEALTHY*. + DRAINING = 3; - // [#not-implemented-hide:] Non-serving port for health checking. - google.protobuf.UInt32Value alt_port = 6; + // Health check timed out. This is part of HDS and is interpreted by Envoy as + // *UNHEALTHY*. + TIMEOUT = 4; - // Reuse health check connection between health checks. Default is true. - google.protobuf.BoolValue reuse_connection = 7; + // Degraded. + DEGRADED = 5; +} +message HealthCheck { // Describes the encoding of the payload bytes in the payload. message Payload { oneof payload { option (validate.required) = true; // Hex encoded payload. E.g., "000000FF". - string text = 1 [(validate.rules).string.min_bytes = 1]; + string text = 1 [(validate.rules).string = {min_bytes: 1}]; // [#not-implemented-hide:] Binary payload. bytes binary = 2; @@ -99,7 +70,7 @@ message HealthCheck { // Specifies the HTTP path that will be requested during health checking. For example // */healthcheck*. - string path = 2 [(validate.rules).string.min_bytes = 1]; + string path = 2 [(validate.rules).string = {min_bytes: 1}]; // [#not-implemented-hide:] HTTP specific payload. Payload send = 3; @@ -116,8 +87,8 @@ message HealthCheck { // health checked cluster. For more information, including details on header value syntax, see // the documentation on :ref:`custom request headers // `. - repeated core.HeaderValueOption request_headers_to_add = 6 - [(validate.rules).repeated .max_items = 1000]; + repeated HeaderValueOption request_headers_to_add = 6 + [(validate.rules).repeated = {max_items: 1000}]; // Specifies a list of HTTP headers that should be removed from each request that is sent to the // health checked cluster. @@ -129,7 +100,7 @@ message HealthCheck { // Specifies a list of HTTP response statuses considered healthy. If provided, replaces default // 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open // semantics of :ref:`Int64Range `. - repeated envoy.type.Int64Range expected_statuses = 9; + repeated type.Int64Range expected_statuses = 9; } message TcpHealthCheck { @@ -171,7 +142,7 @@ message HealthCheck { // Custom health check. message CustomHealthCheck { // The registered name of the custom health checker. - string name = 1 [(validate.rules).string.min_bytes = 1]; + string name = 1 [(validate.rules).string = {min_bytes: 1}]; // A custom health checker specific configuration which depends on the custom health checker // being instantiated. See :api:`envoy/config/health_checker` for reference. @@ -182,6 +153,54 @@ message HealthCheck { } } + reserved 10; + + // The time to wait for a health check response. If the timeout is reached the + // health check attempt will be considered a failure. + google.protobuf.Duration timeout = 1 [(validate.rules).duration = { + required: true + gt {} + }]; + + // The interval between health checks. + google.protobuf.Duration interval = 2 [(validate.rules).duration = { + required: true + gt {} + }]; + + // An optional jitter amount in milliseconds. If specified, Envoy will start health + // checking after for a random time in ms between 0 and initial_jitter. This only + // applies to the first health check. + google.protobuf.Duration initial_jitter = 20; + + // An optional jitter amount in milliseconds. If specified, during every + // interval Envoy will add interval_jitter to the wait time. + google.protobuf.Duration interval_jitter = 3; + + // An optional jitter amount as a percentage of interval_ms. If specified, + // during every interval Envoy will add interval_ms * + // interval_jitter_percent / 100 to the wait time. + // + // If interval_jitter_ms and interval_jitter_percent are both set, both of + // them will be used to increase the wait time. + uint32 interval_jitter_percent = 18; + + // The number of unhealthy health checks required before a host is marked + // unhealthy. Note that for *http* health checking if a host responds with 503 + // this threshold is ignored and the host is considered unhealthy immediately. + google.protobuf.UInt32Value unhealthy_threshold = 4; + + // The number of healthy health checks required before a host is marked + // healthy. Note that during startup, only a single successful health check is + // required to mark a host healthy. + google.protobuf.UInt32Value healthy_threshold = 5; + + // [#not-implemented-hide:] Non-serving port for health checking. + google.protobuf.UInt32Value alt_port = 6; + + // Reuse health check connection between health checks. Default is true. + google.protobuf.BoolValue reuse_connection = 7; + oneof health_checker { option (validate.required) = true; @@ -198,10 +217,6 @@ message HealthCheck { CustomHealthCheck custom_health_check = 13; } - reserved 10; // redis_health_check is deprecated by :ref:`custom_health_check - // ` - reserved "redis_health_check"; - // The "no traffic interval" is a special health check interval that is used when a cluster has // never had traffic routed to it. This lower interval allows cluster information to be kept up to // date, without sending a potentially large amount of active health checking traffic for no @@ -210,14 +225,14 @@ message HealthCheck { // any other. // // The default value for "no traffic interval" is 60 seconds. - google.protobuf.Duration no_traffic_interval = 12 [(validate.rules).duration.gt = {}]; + google.protobuf.Duration no_traffic_interval = 12 [(validate.rules).duration = {gt {}}]; // The "unhealthy interval" is a health check interval that is used for hosts that are marked as // unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the // standard health check interval that is defined. // // The default value for "unhealthy interval" is the same as "interval". - google.protobuf.Duration unhealthy_interval = 14 [(validate.rules).duration.gt = {}]; + google.protobuf.Duration unhealthy_interval = 14 [(validate.rules).duration = {gt {}}]; // The "unhealthy edge interval" is a special health check interval that is used for the first // health check right after a host is marked as unhealthy. For subsequent health checks @@ -225,14 +240,14 @@ message HealthCheck { // check interval that is defined. // // The default value for "unhealthy edge interval" is the same as "unhealthy interval". - google.protobuf.Duration unhealthy_edge_interval = 15 [(validate.rules).duration.gt = {}]; + google.protobuf.Duration unhealthy_edge_interval = 15 [(validate.rules).duration = {gt {}}]; // The "healthy edge interval" is a special health check interval that is used for the first // health check right after a host is marked as healthy. For subsequent health checks // Envoy will shift back to using the standard health check interval that is defined. // // The default value for "healthy edge interval" is the same as the default interval. - google.protobuf.Duration healthy_edge_interval = 16 [(validate.rules).duration.gt = {}]; + google.protobuf.Duration healthy_edge_interval = 16 [(validate.rules).duration = {gt {}}]; // Specifies the path to the :ref:`health check event log `. // If empty, no event log will be written. @@ -243,29 +258,3 @@ message HealthCheck { // The default value is false. bool always_log_health_check_failures = 19; } - -// Endpoint health status. -enum HealthStatus { - // The health status is not known. This is interpreted by Envoy as *HEALTHY*. - UNKNOWN = 0; - - // Healthy. - HEALTHY = 1; - - // Unhealthy. - UNHEALTHY = 2; - - // Connection draining in progress. E.g., - // ``_ - // or - // ``_. - // This is interpreted by Envoy as *UNHEALTHY*. - DRAINING = 3; - - // Health check timed out. This is part of HDS and is interpreted by Envoy as - // *UNHEALTHY*. - TIMEOUT = 4; - - // Degraded. - DEGRADED = 5; -} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/http_uri.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/http_uri.proto index 4c7a594f063..7e4b4dba43c 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/http_uri.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/http_uri.proto @@ -7,12 +7,9 @@ option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2.core"; import "google/protobuf/duration.proto"; -import "gogoproto/gogo.proto"; import "validate/validate.proto"; -option (gogoproto.equal_all) = true; - // [#protodoc-title: HTTP Service URI ] // Envoy external URI descriptor @@ -25,7 +22,7 @@ message HttpUri { // // uri: https://www.googleapis.com/oauth2/v1/certs // - string uri = 1 [(validate.rules).string.min_bytes = 1]; + string uri = 1 [(validate.rules).string = {min_bytes: 1}]; // Specify how `uri` is to be fetched. Today, this requires an explicit // cluster, but in the future we may support dynamic cluster creation or @@ -33,6 +30,7 @@ message HttpUri { // `_. oneof http_upstream_type { option (validate.required) = true; + // A cluster is created in the Envoy "cluster_manager" config // section. This field specifies the cluster name. // @@ -42,13 +40,12 @@ message HttpUri { // // cluster: jwks_cluster // - string cluster = 2 [(validate.rules).string.min_bytes = 1]; + string cluster = 2 [(validate.rules).string = {min_bytes: 1}]; } // Sets the maximum duration in milliseconds that a response can take to arrive upon request. - google.protobuf.Duration timeout = 3 [ - (validate.rules).duration.gte = {}, - (validate.rules).duration.required = true, - (gogoproto.stdduration) = true - ]; + google.protobuf.Duration timeout = 3 [(validate.rules).duration = { + required: true + gte {} + }]; } diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/discovery.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/discovery.proto index a3072a817aa..a8423f5f904 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/discovery.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/discovery.proto @@ -5,16 +5,11 @@ package envoy.api.v2; option java_outer_classname = "DiscoveryProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2"; -option go_package = "v2"; import "envoy/api/v2/core/base.proto"; import "google/protobuf/any.proto"; import "google/rpc/status.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; -option (gogoproto.stable_marshaler_all) = true; // [#protodoc-title: Common discovery API components] @@ -49,8 +44,9 @@ message DiscoveryRequest { // nonce corresponding to DiscoveryResponse being ACK/NACKed. See above // discussion on version_info and the DiscoveryResponse nonce comment. This - // may be empty if no nonce is available, e.g. at startup or for non-stream - // xDS implementations. + // may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, + // or 2) the client has not yet accepted an update in this xDS stream (unlike + // delta, where it is populated only for new explicit ACKs). string response_nonce = 5; // This is populated when the previous :ref:`DiscoveryResponse ` @@ -181,7 +177,7 @@ message DeltaDiscoveryRequest { // When the DeltaDiscoveryRequest is a ACK or NACK message in response // to a previous DeltaDiscoveryResponse, the response_nonce must be the // nonce in the DeltaDiscoveryResponse. - // Otherwise response_nonce must be omitted. + // Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. string response_nonce = 6; // This is populated when the previous :ref:`DiscoveryResponse ` diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/eds.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/eds.proto index d680ef7ea5a..15518902977 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/eds.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/eds.proto @@ -5,7 +5,6 @@ package envoy.api.v2; option java_outer_classname = "EdsProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2"; - option java_generic_services = true; import "envoy/api/v2/discovery.proto"; @@ -13,14 +12,10 @@ import "envoy/api/v2/endpoint/endpoint.proto"; import "envoy/type/percent.proto"; import "google/api/annotations.proto"; - -import "validate/validate.proto"; -import "gogoproto/gogo.proto"; -import "google/protobuf/wrappers.proto"; import "google/protobuf/duration.proto"; +import "google/protobuf/wrappers.proto"; -option (gogoproto.equal_all) = true; -option (gogoproto.stable_marshaler_all) = true; +import "validate/validate.proto"; // [#protodoc-title: EDS] // Endpoint discovery :ref:`architecture overview ` @@ -52,29 +47,18 @@ service EndpointDiscoveryService { // load_balancing_weight of its locality. First, a locality will be selected, // then an endpoint within that locality will be chose based on its weight. message ClusterLoadAssignment { - // Name of the cluster. This will be the :ref:`service_name - // ` value if specified - // in the cluster :ref:`EdsClusterConfig - // `. - string cluster_name = 1 [(validate.rules).string.min_bytes = 1]; - - // List of endpoints to load balance to. - repeated endpoint.LocalityLbEndpoints endpoints = 2; - - // Map of named endpoints that can be referenced in LocalityLbEndpoints. - map named_endpoints = 5; - // Load balancing policy settings. message Policy { - reserved 1; - message DropOverload { // Identifier for the policy specifying the drop. - string category = 1 [(validate.rules).string.min_bytes = 1]; + string category = 1 [(validate.rules).string = {min_bytes: 1}]; // Percentage of traffic that should be dropped for the category. - envoy.type.FractionalPercent drop_percentage = 2; + type.FractionalPercent drop_percentage = 2; } + + reserved 1; + // Action to trim the overall incoming traffic to protect the upstream // hosts. This action allows protection in case the hosts are unable to // recover from an outage, or unable to autoscale or unable to handle @@ -110,15 +94,38 @@ message ClusterLoadAssignment { // // Read more at :ref:`priority levels ` and // :ref:`localities `. - google.protobuf.UInt32Value overprovisioning_factor = 3 [(validate.rules).uint32.gt = 0]; + google.protobuf.UInt32Value overprovisioning_factor = 3 [(validate.rules).uint32 = {gt: 0}]; // The max time until which the endpoints from this assignment can be used. // If no new assignments are received before this time expires the endpoints // are considered stale and should be marked unhealthy. // Defaults to 0 which means endpoints never go stale. - google.protobuf.Duration endpoint_stale_after = 4 [(validate.rules).duration.gt.seconds = 0]; + google.protobuf.Duration endpoint_stale_after = 4 [(validate.rules).duration = {gt {}}]; + + // The flag to disable overprovisioning. If it is set to true, + // :ref:`overprovisioning factor + // ` will be ignored + // and Envoy will not perform graceful failover between priority levels or + // localities as endpoints become unhealthy. Otherwise Envoy will perform + // graceful failover as :ref:`overprovisioning factor + // ` suggests. + // [#next-major-version: Unify with overprovisioning config as a single message.] + // [#not-implemented-hide:] + bool disable_overprovisioning = 5; } + // Name of the cluster. This will be the :ref:`service_name + // ` value if specified + // in the cluster :ref:`EdsClusterConfig + // `. + string cluster_name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // List of endpoints to load balance to. + repeated endpoint.LocalityLbEndpoints endpoints = 2; + + // Map of named endpoints that can be referenced in LocalityLbEndpoints. + map named_endpoints = 5; + // Load balancing policy settings. Policy policy = 4; } diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/endpoint.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/endpoint.proto index 7abb7ea5f3c..46875a173e8 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/endpoint.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/endpoint.proto @@ -5,7 +5,6 @@ package envoy.api.v2.endpoint; option java_outer_classname = "EndpointProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.api.v2.endpoint"; -option go_package = "endpoint"; import "envoy/api/v2/core/address.proto"; import "envoy/api/v2/core/base.proto"; @@ -14,14 +13,22 @@ import "envoy/api/v2/core/health_check.proto"; import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Endpoints] // Upstream host identifier. message Endpoint { + // The optional health check configuration. + message HealthCheckConfig { + // Optional alternative health check port value. + // + // By default the health check address port of an upstream host is the same + // as the host's serving address port. This provides an alternative health + // check port. Setting this with a non-zero value allows an upstream host + // to have different health check address port. + uint32 port_value = 1 [(validate.rules).uint32 = {lte: 65535}]; + } + // The upstream host address. // // .. attention:: @@ -33,17 +40,6 @@ message Endpoint { // and will be resolved via DNS. core.Address address = 1; - // The optional health check configuration. - message HealthCheckConfig { - // Optional alternative health check port value. - // - // By default the health check address port of an upstream host is the same - // as the host's serving address port. This provides an alternative health - // check port. Setting this with a non-zero value allows an upstream host - // to have different health check address port. - uint32 port_value = 1 [(validate.rules).uint32.lte = 65535]; - } - // The optional health check configuration is used as configuration for the // health checker to contact the health checked host. // @@ -59,6 +55,7 @@ message LbEndpoint { // Upstream host identifier or a named reference. oneof host_identifier { Endpoint endpoint = 1; + string endpoint_name = 5; } diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/load_report.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/load_report.proto index df3fd6071e4..b44313ba4ee 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/load_report.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/endpoint/load_report.proto @@ -13,7 +13,6 @@ import "google/protobuf/duration.proto"; import "google/protobuf/struct.proto"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; // These are stats Envoy reports to GLB every so often. Report frequency is // defined by diff --git a/xds/third_party/envoy/src/main/proto/envoy/service/discovery/v2/ads.proto b/xds/third_party/envoy/src/main/proto/envoy/service/discovery/v2/ads.proto index 6a9d044ab4b..63b129069ed 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/service/discovery/v2/ads.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/service/discovery/v2/ads.proto @@ -5,16 +5,10 @@ package envoy.service.discovery.v2; option java_outer_classname = "AdsProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.service.discovery.v2"; -option go_package = "v2"; option java_generic_services = true; import "envoy/api/v2/discovery.proto"; -// [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing -// services: https://github.com/google/protobuf/issues/4221 -message AdsDummy { -} - // [#not-implemented-hide:] Discovery services for endpoints, clusters, routes, // and listeners are retained in the package `envoy.api.v2` for backwards // compatibility with existing management servers. New development in discovery @@ -28,11 +22,16 @@ message AdsDummy { // the multiplexed singleton APIs at the Envoy instance and management server. service AggregatedDiscoveryService { // This is a gRPC-only API. - rpc StreamAggregatedResources(stream envoy.api.v2.DiscoveryRequest) - returns (stream envoy.api.v2.DiscoveryResponse) { + rpc StreamAggregatedResources(stream api.v2.DiscoveryRequest) + returns (stream api.v2.DiscoveryResponse) { } - rpc DeltaAggregatedResources(stream envoy.api.v2.DeltaDiscoveryRequest) - returns (stream envoy.api.v2.DeltaDiscoveryResponse) { + rpc DeltaAggregatedResources(stream api.v2.DeltaDiscoveryRequest) + returns (stream api.v2.DeltaDiscoveryResponse) { } } + +// [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing +// services: https://github.com/google/protobuf/issues/4221 +message AdsDummy { +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/service/load_stats/v2/lrs.proto b/xds/third_party/envoy/src/main/proto/envoy/service/load_stats/v2/lrs.proto index 2fe95f3b6a9..d7029db0b5e 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/service/load_stats/v2/lrs.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/service/load_stats/v2/lrs.proto @@ -5,7 +5,6 @@ package envoy.service.load_stats.v2; option java_outer_classname = "LrsProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.service.load_stats.v2"; -option go_package = "v2"; option java_generic_services = true; import "envoy/api/v2/core/base.proto"; diff --git a/xds/third_party/envoy/src/main/proto/envoy/type/percent.proto b/xds/third_party/envoy/src/main/proto/envoy/type/percent.proto index 551e93bfdd1..6d0868fd0ed 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/type/percent.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/type/percent.proto @@ -7,15 +7,12 @@ option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.type"; import "validate/validate.proto"; -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Percent] // Identifies a percentage, in the range [0.0, 100.0]. message Percent { - double value = 1 [(validate.rules).double = {gte: 0, lte: 100}]; + double value = 1 [(validate.rules).double = {lte: 100.0 gte: 0.0}]; } // A fractional percentage is used in cases in which for performance reasons performing floating @@ -25,9 +22,6 @@ message Percent { // * **Example**: 1/100 = 1%. // * **Example**: 3/10000 = 0.03%. message FractionalPercent { - // Specifies the numerator. Defaults to 0. - uint32 numerator = 1; - // Fraction percentages support several fixed denominator values. enum DenominatorType { // 100. @@ -46,7 +40,10 @@ message FractionalPercent { MILLION = 2; } + // Specifies the numerator. Defaults to 0. + uint32 numerator = 1; + // Specifies the denominator. If the denominator specified is less than the numerator, the final // fractional percentage is capped at 1 (100%). - DenominatorType denominator = 2 [(validate.rules).enum.defined_only = true]; + DenominatorType denominator = 2 [(validate.rules).enum = {defined_only: true}]; } diff --git a/xds/third_party/envoy/src/main/proto/envoy/type/range.proto b/xds/third_party/envoy/src/main/proto/envoy/type/range.proto index e64b71e440f..f31cf32f07c 100644 --- a/xds/third_party/envoy/src/main/proto/envoy/type/range.proto +++ b/xds/third_party/envoy/src/main/proto/envoy/type/range.proto @@ -5,11 +5,6 @@ package envoy.type; option java_outer_classname = "RangeProto"; option java_multiple_files = true; option java_package = "io.envoyproxy.envoy.type"; -option go_package = "envoy_type"; - -import "gogoproto/gogo.proto"; - -option (gogoproto.equal_all) = true; // [#protodoc-title: Range] From b5ddf3ef08f1bfc08c7b3637b21e5054358ec63f Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Thu, 17 Oct 2019 18:29:07 -0700 Subject: [PATCH 107/131] xds: import proto files for CDS, LDS, RDS from envoy repo (#6292) --- .../api/v2/ClusterDiscoveryServiceGrpc.java | 419 +++++ .../api/v2/ListenerDiscoveryServiceGrpc.java | 434 +++++ .../api/v2/RouteDiscoveryServiceGrpc.java | 439 ++++++ .../v2/VirtualHostDiscoveryServiceGrpc.java | 332 ++++ xds/third_party/envoy/import.sh | 13 + .../src/main/proto/envoy/api/v2/cds.proto | 830 ++++++++++ .../api/v2/cluster/circuit_breaker.proto | 64 + .../proto/envoy/api/v2/cluster/filter.proto | 26 + .../api/v2/cluster/outlier_detection.proto | 146 ++ .../proto/envoy/api/v2/core/protocol.proto | 152 ++ .../src/main/proto/envoy/api/v2/lds.proto | 217 +++ .../envoy/api/v2/listener/listener.proto | 208 +++ .../api/v2/listener/udp_listener_config.proto | 30 + .../src/main/proto/envoy/api/v2/rds.proto | 131 ++ .../main/proto/envoy/api/v2/route/route.proto | 1398 +++++++++++++++++ .../config/listener/v2/api_listener.proto | 24 + .../main/proto/envoy/type/matcher/regex.proto | 37 + .../proto/envoy/type/matcher/string.proto | 66 + 18 files changed, 4966 insertions(+) create mode 100644 xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java create mode 100644 xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java create mode 100644 xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java create mode 100644 xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/cds.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/circuit_breaker.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/filter.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/outlier_detection.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/core/protocol.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/lds.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/listener.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/udp_listener_config.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/rds.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/route/route.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/config/listener/v2/api_listener.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/type/matcher/regex.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/type/matcher/string.proto diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java new file mode 100644 index 00000000000..d812191e7da --- /dev/null +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java @@ -0,0 +1,419 @@ +package io.envoyproxy.envoy.api.v2; + +import static io.grpc.MethodDescriptor.generateFullMethodName; +import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ClientCalls.asyncClientStreamingCall; +import static io.grpc.stub.ClientCalls.asyncServerStreamingCall; +import static io.grpc.stub.ClientCalls.asyncUnaryCall; +import static io.grpc.stub.ClientCalls.blockingServerStreamingCall; +import static io.grpc.stub.ClientCalls.blockingUnaryCall; +import static io.grpc.stub.ClientCalls.futureUnaryCall; +import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ServerCalls.asyncClientStreamingCall; +import static io.grpc.stub.ServerCalls.asyncServerStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; + +/** + *

    + * Return list of all clusters this proxy will load balance to.
    + * 
    + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler", + comments = "Source: envoy/api/v2/cds.proto") +public final class ClusterDiscoveryServiceGrpc { + + private ClusterDiscoveryServiceGrpc() {} + + public static final String SERVICE_NAME = "envoy.api.v2.ClusterDiscoveryService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getStreamClustersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "StreamClusters", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getStreamClustersMethod() { + io.grpc.MethodDescriptor getStreamClustersMethod; + if ((getStreamClustersMethod = ClusterDiscoveryServiceGrpc.getStreamClustersMethod) == null) { + synchronized (ClusterDiscoveryServiceGrpc.class) { + if ((getStreamClustersMethod = ClusterDiscoveryServiceGrpc.getStreamClustersMethod) == null) { + ClusterDiscoveryServiceGrpc.getStreamClustersMethod = getStreamClustersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "StreamClusters")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ClusterDiscoveryServiceMethodDescriptorSupplier("StreamClusters")) + .build(); + } + } + } + return getStreamClustersMethod; + } + + private static volatile io.grpc.MethodDescriptor getDeltaClustersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeltaClusters", + requestType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getDeltaClustersMethod() { + io.grpc.MethodDescriptor getDeltaClustersMethod; + if ((getDeltaClustersMethod = ClusterDiscoveryServiceGrpc.getDeltaClustersMethod) == null) { + synchronized (ClusterDiscoveryServiceGrpc.class) { + if ((getDeltaClustersMethod = ClusterDiscoveryServiceGrpc.getDeltaClustersMethod) == null) { + ClusterDiscoveryServiceGrpc.getDeltaClustersMethod = getDeltaClustersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeltaClusters")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ClusterDiscoveryServiceMethodDescriptorSupplier("DeltaClusters")) + .build(); + } + } + } + return getDeltaClustersMethod; + } + + private static volatile io.grpc.MethodDescriptor getFetchClustersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "FetchClusters", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getFetchClustersMethod() { + io.grpc.MethodDescriptor getFetchClustersMethod; + if ((getFetchClustersMethod = ClusterDiscoveryServiceGrpc.getFetchClustersMethod) == null) { + synchronized (ClusterDiscoveryServiceGrpc.class) { + if ((getFetchClustersMethod = ClusterDiscoveryServiceGrpc.getFetchClustersMethod) == null) { + ClusterDiscoveryServiceGrpc.getFetchClustersMethod = getFetchClustersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "FetchClusters")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ClusterDiscoveryServiceMethodDescriptorSupplier("FetchClusters")) + .build(); + } + } + } + return getFetchClustersMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static ClusterDiscoveryServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ClusterDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ClusterDiscoveryServiceStub(channel, callOptions); + } + }; + return ClusterDiscoveryServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static ClusterDiscoveryServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ClusterDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ClusterDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return ClusterDiscoveryServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static ClusterDiscoveryServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ClusterDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ClusterDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return ClusterDiscoveryServiceFutureStub.newStub(factory, channel); + } + + /** + *
    +   * Return list of all clusters this proxy will load balance to.
    +   * 
    + */ + public static abstract class ClusterDiscoveryServiceImplBase implements io.grpc.BindableService { + + /** + */ + public io.grpc.stub.StreamObserver streamClusters( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getStreamClustersMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaClusters( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getDeltaClustersMethod(), responseObserver); + } + + /** + */ + public void fetchClusters(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getFetchClustersMethod(), responseObserver); + } + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getStreamClustersMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_STREAM_CLUSTERS))) + .addMethod( + getDeltaClustersMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest, + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse>( + this, METHODID_DELTA_CLUSTERS))) + .addMethod( + getFetchClustersMethod(), + asyncUnaryCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_FETCH_CLUSTERS))) + .build(); + } + } + + /** + *
    +   * Return list of all clusters this proxy will load balance to.
    +   * 
    + */ + public static final class ClusterDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ClusterDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ClusterDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ClusterDiscoveryServiceStub(channel, callOptions); + } + + /** + */ + public io.grpc.stub.StreamObserver streamClusters( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getStreamClustersMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaClusters( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getDeltaClustersMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void fetchClusters(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getFetchClustersMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + *
    +   * Return list of all clusters this proxy will load balance to.
    +   * 
    + */ + public static final class ClusterDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ClusterDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ClusterDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ClusterDiscoveryServiceBlockingStub(channel, callOptions); + } + + /** + */ + public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchClusters(io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return blockingUnaryCall( + getChannel(), getFetchClustersMethod(), getCallOptions(), request); + } + } + + /** + *
    +   * Return list of all clusters this proxy will load balance to.
    +   * 
    + */ + public static final class ClusterDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ClusterDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ClusterDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ClusterDiscoveryServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture fetchClusters( + io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return futureUnaryCall( + getChannel().newCall(getFetchClustersMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_FETCH_CLUSTERS = 0; + private static final int METHODID_STREAM_CLUSTERS = 1; + private static final int METHODID_DELTA_CLUSTERS = 2; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final ClusterDiscoveryServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(ClusterDiscoveryServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_FETCH_CLUSTERS: + serviceImpl.fetchClusters((io.envoyproxy.envoy.api.v2.DiscoveryRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_STREAM_CLUSTERS: + return (io.grpc.stub.StreamObserver) serviceImpl.streamClusters( + (io.grpc.stub.StreamObserver) responseObserver); + case METHODID_DELTA_CLUSTERS: + return (io.grpc.stub.StreamObserver) serviceImpl.deltaClusters( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class ClusterDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + ClusterDiscoveryServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return io.envoyproxy.envoy.api.v2.CdsProto.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("ClusterDiscoveryService"); + } + } + + private static final class ClusterDiscoveryServiceFileDescriptorSupplier + extends ClusterDiscoveryServiceBaseDescriptorSupplier { + ClusterDiscoveryServiceFileDescriptorSupplier() {} + } + + private static final class ClusterDiscoveryServiceMethodDescriptorSupplier + extends ClusterDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + ClusterDiscoveryServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (ClusterDiscoveryServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new ClusterDiscoveryServiceFileDescriptorSupplier()) + .addMethod(getStreamClustersMethod()) + .addMethod(getDeltaClustersMethod()) + .addMethod(getFetchClustersMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java new file mode 100644 index 00000000000..f772eb15e48 --- /dev/null +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java @@ -0,0 +1,434 @@ +package io.envoyproxy.envoy.api.v2; + +import static io.grpc.MethodDescriptor.generateFullMethodName; +import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ClientCalls.asyncClientStreamingCall; +import static io.grpc.stub.ClientCalls.asyncServerStreamingCall; +import static io.grpc.stub.ClientCalls.asyncUnaryCall; +import static io.grpc.stub.ClientCalls.blockingServerStreamingCall; +import static io.grpc.stub.ClientCalls.blockingUnaryCall; +import static io.grpc.stub.ClientCalls.futureUnaryCall; +import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ServerCalls.asyncClientStreamingCall; +import static io.grpc.stub.ServerCalls.asyncServerStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; + +/** + *
    + * The Envoy instance initiates an RPC at startup to discover a list of
    + * listeners. Updates are delivered via streaming from the LDS server and
    + * consist of a complete update of all listeners. Existing connections will be
    + * allowed to drain from listeners that are no longer present.
    + * 
    + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler", + comments = "Source: envoy/api/v2/lds.proto") +public final class ListenerDiscoveryServiceGrpc { + + private ListenerDiscoveryServiceGrpc() {} + + public static final String SERVICE_NAME = "envoy.api.v2.ListenerDiscoveryService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getDeltaListenersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeltaListeners", + requestType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getDeltaListenersMethod() { + io.grpc.MethodDescriptor getDeltaListenersMethod; + if ((getDeltaListenersMethod = ListenerDiscoveryServiceGrpc.getDeltaListenersMethod) == null) { + synchronized (ListenerDiscoveryServiceGrpc.class) { + if ((getDeltaListenersMethod = ListenerDiscoveryServiceGrpc.getDeltaListenersMethod) == null) { + ListenerDiscoveryServiceGrpc.getDeltaListenersMethod = getDeltaListenersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeltaListeners")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ListenerDiscoveryServiceMethodDescriptorSupplier("DeltaListeners")) + .build(); + } + } + } + return getDeltaListenersMethod; + } + + private static volatile io.grpc.MethodDescriptor getStreamListenersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "StreamListeners", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getStreamListenersMethod() { + io.grpc.MethodDescriptor getStreamListenersMethod; + if ((getStreamListenersMethod = ListenerDiscoveryServiceGrpc.getStreamListenersMethod) == null) { + synchronized (ListenerDiscoveryServiceGrpc.class) { + if ((getStreamListenersMethod = ListenerDiscoveryServiceGrpc.getStreamListenersMethod) == null) { + ListenerDiscoveryServiceGrpc.getStreamListenersMethod = getStreamListenersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "StreamListeners")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ListenerDiscoveryServiceMethodDescriptorSupplier("StreamListeners")) + .build(); + } + } + } + return getStreamListenersMethod; + } + + private static volatile io.grpc.MethodDescriptor getFetchListenersMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "FetchListeners", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getFetchListenersMethod() { + io.grpc.MethodDescriptor getFetchListenersMethod; + if ((getFetchListenersMethod = ListenerDiscoveryServiceGrpc.getFetchListenersMethod) == null) { + synchronized (ListenerDiscoveryServiceGrpc.class) { + if ((getFetchListenersMethod = ListenerDiscoveryServiceGrpc.getFetchListenersMethod) == null) { + ListenerDiscoveryServiceGrpc.getFetchListenersMethod = getFetchListenersMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "FetchListeners")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ListenerDiscoveryServiceMethodDescriptorSupplier("FetchListeners")) + .build(); + } + } + } + return getFetchListenersMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static ListenerDiscoveryServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ListenerDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ListenerDiscoveryServiceStub(channel, callOptions); + } + }; + return ListenerDiscoveryServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static ListenerDiscoveryServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ListenerDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ListenerDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return ListenerDiscoveryServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static ListenerDiscoveryServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ListenerDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ListenerDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return ListenerDiscoveryServiceFutureStub.newStub(factory, channel); + } + + /** + *
    +   * The Envoy instance initiates an RPC at startup to discover a list of
    +   * listeners. Updates are delivered via streaming from the LDS server and
    +   * consist of a complete update of all listeners. Existing connections will be
    +   * allowed to drain from listeners that are no longer present.
    +   * 
    + */ + public static abstract class ListenerDiscoveryServiceImplBase implements io.grpc.BindableService { + + /** + */ + public io.grpc.stub.StreamObserver deltaListeners( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getDeltaListenersMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver streamListeners( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getStreamListenersMethod(), responseObserver); + } + + /** + */ + public void fetchListeners(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getFetchListenersMethod(), responseObserver); + } + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getDeltaListenersMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest, + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse>( + this, METHODID_DELTA_LISTENERS))) + .addMethod( + getStreamListenersMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_STREAM_LISTENERS))) + .addMethod( + getFetchListenersMethod(), + asyncUnaryCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_FETCH_LISTENERS))) + .build(); + } + } + + /** + *
    +   * The Envoy instance initiates an RPC at startup to discover a list of
    +   * listeners. Updates are delivered via streaming from the LDS server and
    +   * consist of a complete update of all listeners. Existing connections will be
    +   * allowed to drain from listeners that are no longer present.
    +   * 
    + */ + public static final class ListenerDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ListenerDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ListenerDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ListenerDiscoveryServiceStub(channel, callOptions); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaListeners( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getDeltaListenersMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver streamListeners( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getStreamListenersMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void fetchListeners(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getFetchListenersMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + *
    +   * The Envoy instance initiates an RPC at startup to discover a list of
    +   * listeners. Updates are delivered via streaming from the LDS server and
    +   * consist of a complete update of all listeners. Existing connections will be
    +   * allowed to drain from listeners that are no longer present.
    +   * 
    + */ + public static final class ListenerDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ListenerDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ListenerDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ListenerDiscoveryServiceBlockingStub(channel, callOptions); + } + + /** + */ + public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchListeners(io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return blockingUnaryCall( + getChannel(), getFetchListenersMethod(), getCallOptions(), request); + } + } + + /** + *
    +   * The Envoy instance initiates an RPC at startup to discover a list of
    +   * listeners. Updates are delivered via streaming from the LDS server and
    +   * consist of a complete update of all listeners. Existing connections will be
    +   * allowed to drain from listeners that are no longer present.
    +   * 
    + */ + public static final class ListenerDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ListenerDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ListenerDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ListenerDiscoveryServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture fetchListeners( + io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return futureUnaryCall( + getChannel().newCall(getFetchListenersMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_FETCH_LISTENERS = 0; + private static final int METHODID_DELTA_LISTENERS = 1; + private static final int METHODID_STREAM_LISTENERS = 2; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final ListenerDiscoveryServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(ListenerDiscoveryServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_FETCH_LISTENERS: + serviceImpl.fetchListeners((io.envoyproxy.envoy.api.v2.DiscoveryRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_DELTA_LISTENERS: + return (io.grpc.stub.StreamObserver) serviceImpl.deltaListeners( + (io.grpc.stub.StreamObserver) responseObserver); + case METHODID_STREAM_LISTENERS: + return (io.grpc.stub.StreamObserver) serviceImpl.streamListeners( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class ListenerDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + ListenerDiscoveryServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return io.envoyproxy.envoy.api.v2.LdsProto.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("ListenerDiscoveryService"); + } + } + + private static final class ListenerDiscoveryServiceFileDescriptorSupplier + extends ListenerDiscoveryServiceBaseDescriptorSupplier { + ListenerDiscoveryServiceFileDescriptorSupplier() {} + } + + private static final class ListenerDiscoveryServiceMethodDescriptorSupplier + extends ListenerDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + ListenerDiscoveryServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (ListenerDiscoveryServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new ListenerDiscoveryServiceFileDescriptorSupplier()) + .addMethod(getDeltaListenersMethod()) + .addMethod(getStreamListenersMethod()) + .addMethod(getFetchListenersMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java new file mode 100644 index 00000000000..f22418224dc --- /dev/null +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java @@ -0,0 +1,439 @@ +package io.envoyproxy.envoy.api.v2; + +import static io.grpc.MethodDescriptor.generateFullMethodName; +import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ClientCalls.asyncClientStreamingCall; +import static io.grpc.stub.ClientCalls.asyncServerStreamingCall; +import static io.grpc.stub.ClientCalls.asyncUnaryCall; +import static io.grpc.stub.ClientCalls.blockingServerStreamingCall; +import static io.grpc.stub.ClientCalls.blockingUnaryCall; +import static io.grpc.stub.ClientCalls.futureUnaryCall; +import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ServerCalls.asyncClientStreamingCall; +import static io.grpc.stub.ServerCalls.asyncServerStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; + +/** + *
    + * The resource_names field in DiscoveryRequest specifies a route configuration.
    + * This allows an Envoy configuration with multiple HTTP listeners (and
    + * associated HTTP connection manager filters) to use different route
    + * configurations. Each listener will bind its HTTP connection manager filter to
    + * a route table via this identifier.
    + * 
    + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler", + comments = "Source: envoy/api/v2/rds.proto") +public final class RouteDiscoveryServiceGrpc { + + private RouteDiscoveryServiceGrpc() {} + + public static final String SERVICE_NAME = "envoy.api.v2.RouteDiscoveryService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getStreamRoutesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "StreamRoutes", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getStreamRoutesMethod() { + io.grpc.MethodDescriptor getStreamRoutesMethod; + if ((getStreamRoutesMethod = RouteDiscoveryServiceGrpc.getStreamRoutesMethod) == null) { + synchronized (RouteDiscoveryServiceGrpc.class) { + if ((getStreamRoutesMethod = RouteDiscoveryServiceGrpc.getStreamRoutesMethod) == null) { + RouteDiscoveryServiceGrpc.getStreamRoutesMethod = getStreamRoutesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "StreamRoutes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new RouteDiscoveryServiceMethodDescriptorSupplier("StreamRoutes")) + .build(); + } + } + } + return getStreamRoutesMethod; + } + + private static volatile io.grpc.MethodDescriptor getDeltaRoutesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeltaRoutes", + requestType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getDeltaRoutesMethod() { + io.grpc.MethodDescriptor getDeltaRoutesMethod; + if ((getDeltaRoutesMethod = RouteDiscoveryServiceGrpc.getDeltaRoutesMethod) == null) { + synchronized (RouteDiscoveryServiceGrpc.class) { + if ((getDeltaRoutesMethod = RouteDiscoveryServiceGrpc.getDeltaRoutesMethod) == null) { + RouteDiscoveryServiceGrpc.getDeltaRoutesMethod = getDeltaRoutesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeltaRoutes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new RouteDiscoveryServiceMethodDescriptorSupplier("DeltaRoutes")) + .build(); + } + } + } + return getDeltaRoutesMethod; + } + + private static volatile io.grpc.MethodDescriptor getFetchRoutesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "FetchRoutes", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getFetchRoutesMethod() { + io.grpc.MethodDescriptor getFetchRoutesMethod; + if ((getFetchRoutesMethod = RouteDiscoveryServiceGrpc.getFetchRoutesMethod) == null) { + synchronized (RouteDiscoveryServiceGrpc.class) { + if ((getFetchRoutesMethod = RouteDiscoveryServiceGrpc.getFetchRoutesMethod) == null) { + RouteDiscoveryServiceGrpc.getFetchRoutesMethod = getFetchRoutesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "FetchRoutes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new RouteDiscoveryServiceMethodDescriptorSupplier("FetchRoutes")) + .build(); + } + } + } + return getFetchRoutesMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static RouteDiscoveryServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public RouteDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new RouteDiscoveryServiceStub(channel, callOptions); + } + }; + return RouteDiscoveryServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static RouteDiscoveryServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public RouteDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new RouteDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return RouteDiscoveryServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static RouteDiscoveryServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public RouteDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new RouteDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return RouteDiscoveryServiceFutureStub.newStub(factory, channel); + } + + /** + *
    +   * The resource_names field in DiscoveryRequest specifies a route configuration.
    +   * This allows an Envoy configuration with multiple HTTP listeners (and
    +   * associated HTTP connection manager filters) to use different route
    +   * configurations. Each listener will bind its HTTP connection manager filter to
    +   * a route table via this identifier.
    +   * 
    + */ + public static abstract class RouteDiscoveryServiceImplBase implements io.grpc.BindableService { + + /** + */ + public io.grpc.stub.StreamObserver streamRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getStreamRoutesMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getDeltaRoutesMethod(), responseObserver); + } + + /** + */ + public void fetchRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getFetchRoutesMethod(), responseObserver); + } + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getStreamRoutesMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_STREAM_ROUTES))) + .addMethod( + getDeltaRoutesMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest, + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse>( + this, METHODID_DELTA_ROUTES))) + .addMethod( + getFetchRoutesMethod(), + asyncUnaryCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_FETCH_ROUTES))) + .build(); + } + } + + /** + *
    +   * The resource_names field in DiscoveryRequest specifies a route configuration.
    +   * This allows an Envoy configuration with multiple HTTP listeners (and
    +   * associated HTTP connection manager filters) to use different route
    +   * configurations. Each listener will bind its HTTP connection manager filter to
    +   * a route table via this identifier.
    +   * 
    + */ + public static final class RouteDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private RouteDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected RouteDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new RouteDiscoveryServiceStub(channel, callOptions); + } + + /** + */ + public io.grpc.stub.StreamObserver streamRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getStreamRoutesMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getDeltaRoutesMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void fetchRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getFetchRoutesMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + *
    +   * The resource_names field in DiscoveryRequest specifies a route configuration.
    +   * This allows an Envoy configuration with multiple HTTP listeners (and
    +   * associated HTTP connection manager filters) to use different route
    +   * configurations. Each listener will bind its HTTP connection manager filter to
    +   * a route table via this identifier.
    +   * 
    + */ + public static final class RouteDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private RouteDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected RouteDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new RouteDiscoveryServiceBlockingStub(channel, callOptions); + } + + /** + */ + public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return blockingUnaryCall( + getChannel(), getFetchRoutesMethod(), getCallOptions(), request); + } + } + + /** + *
    +   * The resource_names field in DiscoveryRequest specifies a route configuration.
    +   * This allows an Envoy configuration with multiple HTTP listeners (and
    +   * associated HTTP connection manager filters) to use different route
    +   * configurations. Each listener will bind its HTTP connection manager filter to
    +   * a route table via this identifier.
    +   * 
    + */ + public static final class RouteDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private RouteDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected RouteDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new RouteDiscoveryServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture fetchRoutes( + io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return futureUnaryCall( + getChannel().newCall(getFetchRoutesMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_FETCH_ROUTES = 0; + private static final int METHODID_STREAM_ROUTES = 1; + private static final int METHODID_DELTA_ROUTES = 2; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final RouteDiscoveryServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(RouteDiscoveryServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_FETCH_ROUTES: + serviceImpl.fetchRoutes((io.envoyproxy.envoy.api.v2.DiscoveryRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_STREAM_ROUTES: + return (io.grpc.stub.StreamObserver) serviceImpl.streamRoutes( + (io.grpc.stub.StreamObserver) responseObserver); + case METHODID_DELTA_ROUTES: + return (io.grpc.stub.StreamObserver) serviceImpl.deltaRoutes( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class RouteDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + RouteDiscoveryServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return io.envoyproxy.envoy.api.v2.RdsProto.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("RouteDiscoveryService"); + } + } + + private static final class RouteDiscoveryServiceFileDescriptorSupplier + extends RouteDiscoveryServiceBaseDescriptorSupplier { + RouteDiscoveryServiceFileDescriptorSupplier() {} + } + + private static final class RouteDiscoveryServiceMethodDescriptorSupplier + extends RouteDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + RouteDiscoveryServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (RouteDiscoveryServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new RouteDiscoveryServiceFileDescriptorSupplier()) + .addMethod(getStreamRoutesMethod()) + .addMethod(getDeltaRoutesMethod()) + .addMethod(getFetchRoutesMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java new file mode 100644 index 00000000000..dac821b715e --- /dev/null +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java @@ -0,0 +1,332 @@ +package io.envoyproxy.envoy.api.v2; + +import static io.grpc.MethodDescriptor.generateFullMethodName; +import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ClientCalls.asyncClientStreamingCall; +import static io.grpc.stub.ClientCalls.asyncServerStreamingCall; +import static io.grpc.stub.ClientCalls.asyncUnaryCall; +import static io.grpc.stub.ClientCalls.blockingServerStreamingCall; +import static io.grpc.stub.ClientCalls.blockingUnaryCall; +import static io.grpc.stub.ClientCalls.futureUnaryCall; +import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ServerCalls.asyncClientStreamingCall; +import static io.grpc.stub.ServerCalls.asyncServerStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; + +/** + *
    + * Virtual Host Discovery Service (VHDS) is used to dynamically update the list of virtual hosts for
    + * a given RouteConfiguration. If VHDS is configured a virtual host list update will be triggered
    + * during the processing of an HTTP request if a route for the request cannot be resolved. The
    + * :ref:`resource_names_subscribe <envoy_api_msg_DeltaDiscoveryRequest.resource_names_subscribe>`
    + * field contains a list of virtual host names or aliases to track. The contents of an alias would
    + * be the contents of a *host* or *authority* header used to make an http request. An xDS server
    + * will match an alias to a virtual host based on the content of :ref:`domains'
    + * <envoy_api_msg_route.VirtualHost.domains>` field. The *resource_names_unsubscribe* field contains
    + * a list of virtual host names that have been :ref:`unsubscribed <xds_protocol_unsubscribe>`
    + * from the routing table associated with the RouteConfiguration.
    + * 
    + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler", + comments = "Source: envoy/api/v2/rds.proto") +public final class VirtualHostDiscoveryServiceGrpc { + + private VirtualHostDiscoveryServiceGrpc() {} + + public static final String SERVICE_NAME = "envoy.api.v2.VirtualHostDiscoveryService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getDeltaVirtualHostsMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeltaVirtualHosts", + requestType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getDeltaVirtualHostsMethod() { + io.grpc.MethodDescriptor getDeltaVirtualHostsMethod; + if ((getDeltaVirtualHostsMethod = VirtualHostDiscoveryServiceGrpc.getDeltaVirtualHostsMethod) == null) { + synchronized (VirtualHostDiscoveryServiceGrpc.class) { + if ((getDeltaVirtualHostsMethod = VirtualHostDiscoveryServiceGrpc.getDeltaVirtualHostsMethod) == null) { + VirtualHostDiscoveryServiceGrpc.getDeltaVirtualHostsMethod = getDeltaVirtualHostsMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeltaVirtualHosts")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new VirtualHostDiscoveryServiceMethodDescriptorSupplier("DeltaVirtualHosts")) + .build(); + } + } + } + return getDeltaVirtualHostsMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static VirtualHostDiscoveryServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public VirtualHostDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new VirtualHostDiscoveryServiceStub(channel, callOptions); + } + }; + return VirtualHostDiscoveryServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static VirtualHostDiscoveryServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public VirtualHostDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new VirtualHostDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return VirtualHostDiscoveryServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static VirtualHostDiscoveryServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public VirtualHostDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new VirtualHostDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return VirtualHostDiscoveryServiceFutureStub.newStub(factory, channel); + } + + /** + *
    +   * Virtual Host Discovery Service (VHDS) is used to dynamically update the list of virtual hosts for
    +   * a given RouteConfiguration. If VHDS is configured a virtual host list update will be triggered
    +   * during the processing of an HTTP request if a route for the request cannot be resolved. The
    +   * :ref:`resource_names_subscribe <envoy_api_msg_DeltaDiscoveryRequest.resource_names_subscribe>`
    +   * field contains a list of virtual host names or aliases to track. The contents of an alias would
    +   * be the contents of a *host* or *authority* header used to make an http request. An xDS server
    +   * will match an alias to a virtual host based on the content of :ref:`domains'
    +   * <envoy_api_msg_route.VirtualHost.domains>` field. The *resource_names_unsubscribe* field contains
    +   * a list of virtual host names that have been :ref:`unsubscribed <xds_protocol_unsubscribe>`
    +   * from the routing table associated with the RouteConfiguration.
    +   * 
    + */ + public static abstract class VirtualHostDiscoveryServiceImplBase implements io.grpc.BindableService { + + /** + */ + public io.grpc.stub.StreamObserver deltaVirtualHosts( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getDeltaVirtualHostsMethod(), responseObserver); + } + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getDeltaVirtualHostsMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest, + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse>( + this, METHODID_DELTA_VIRTUAL_HOSTS))) + .build(); + } + } + + /** + *
    +   * Virtual Host Discovery Service (VHDS) is used to dynamically update the list of virtual hosts for
    +   * a given RouteConfiguration. If VHDS is configured a virtual host list update will be triggered
    +   * during the processing of an HTTP request if a route for the request cannot be resolved. The
    +   * :ref:`resource_names_subscribe <envoy_api_msg_DeltaDiscoveryRequest.resource_names_subscribe>`
    +   * field contains a list of virtual host names or aliases to track. The contents of an alias would
    +   * be the contents of a *host* or *authority* header used to make an http request. An xDS server
    +   * will match an alias to a virtual host based on the content of :ref:`domains'
    +   * <envoy_api_msg_route.VirtualHost.domains>` field. The *resource_names_unsubscribe* field contains
    +   * a list of virtual host names that have been :ref:`unsubscribed <xds_protocol_unsubscribe>`
    +   * from the routing table associated with the RouteConfiguration.
    +   * 
    + */ + public static final class VirtualHostDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private VirtualHostDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected VirtualHostDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new VirtualHostDiscoveryServiceStub(channel, callOptions); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaVirtualHosts( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getDeltaVirtualHostsMethod(), getCallOptions()), responseObserver); + } + } + + /** + *
    +   * Virtual Host Discovery Service (VHDS) is used to dynamically update the list of virtual hosts for
    +   * a given RouteConfiguration. If VHDS is configured a virtual host list update will be triggered
    +   * during the processing of an HTTP request if a route for the request cannot be resolved. The
    +   * :ref:`resource_names_subscribe <envoy_api_msg_DeltaDiscoveryRequest.resource_names_subscribe>`
    +   * field contains a list of virtual host names or aliases to track. The contents of an alias would
    +   * be the contents of a *host* or *authority* header used to make an http request. An xDS server
    +   * will match an alias to a virtual host based on the content of :ref:`domains'
    +   * <envoy_api_msg_route.VirtualHost.domains>` field. The *resource_names_unsubscribe* field contains
    +   * a list of virtual host names that have been :ref:`unsubscribed <xds_protocol_unsubscribe>`
    +   * from the routing table associated with the RouteConfiguration.
    +   * 
    + */ + public static final class VirtualHostDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private VirtualHostDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected VirtualHostDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new VirtualHostDiscoveryServiceBlockingStub(channel, callOptions); + } + } + + /** + *
    +   * Virtual Host Discovery Service (VHDS) is used to dynamically update the list of virtual hosts for
    +   * a given RouteConfiguration. If VHDS is configured a virtual host list update will be triggered
    +   * during the processing of an HTTP request if a route for the request cannot be resolved. The
    +   * :ref:`resource_names_subscribe <envoy_api_msg_DeltaDiscoveryRequest.resource_names_subscribe>`
    +   * field contains a list of virtual host names or aliases to track. The contents of an alias would
    +   * be the contents of a *host* or *authority* header used to make an http request. An xDS server
    +   * will match an alias to a virtual host based on the content of :ref:`domains'
    +   * <envoy_api_msg_route.VirtualHost.domains>` field. The *resource_names_unsubscribe* field contains
    +   * a list of virtual host names that have been :ref:`unsubscribed <xds_protocol_unsubscribe>`
    +   * from the routing table associated with the RouteConfiguration.
    +   * 
    + */ + public static final class VirtualHostDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private VirtualHostDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected VirtualHostDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new VirtualHostDiscoveryServiceFutureStub(channel, callOptions); + } + } + + private static final int METHODID_DELTA_VIRTUAL_HOSTS = 0; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final VirtualHostDiscoveryServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(VirtualHostDiscoveryServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_DELTA_VIRTUAL_HOSTS: + return (io.grpc.stub.StreamObserver) serviceImpl.deltaVirtualHosts( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class VirtualHostDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + VirtualHostDiscoveryServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return io.envoyproxy.envoy.api.v2.RdsProto.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("VirtualHostDiscoveryService"); + } + } + + private static final class VirtualHostDiscoveryServiceFileDescriptorSupplier + extends VirtualHostDiscoveryServiceBaseDescriptorSupplier { + VirtualHostDiscoveryServiceFileDescriptorSupplier() {} + } + + private static final class VirtualHostDiscoveryServiceMethodDescriptorSupplier + extends VirtualHostDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + VirtualHostDiscoveryServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (VirtualHostDiscoveryServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new VirtualHostDiscoveryServiceFileDescriptorSupplier()) + .addMethod(getDeltaVirtualHostsMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/xds/third_party/envoy/import.sh b/xds/third_party/envoy/import.sh index 0a4b44738b1..dab909c62fe 100755 --- a/xds/third_party/envoy/import.sh +++ b/xds/third_party/envoy/import.sh @@ -25,18 +25,31 @@ SOURCE_PROTO_BASE_DIR=envoy/api TARGET_PROTO_BASE_DIR=src/main/proto FILES=( envoy/api/v2/auth/cert.proto +envoy/api/v2/cds.proto +envoy/api/v2/cluster/circuit_breaker.proto +envoy/api/v2/cluster/filter.proto +envoy/api/v2/cluster/outlier_detection.proto envoy/api/v2/core/address.proto envoy/api/v2/core/base.proto envoy/api/v2/core/config_source.proto envoy/api/v2/core/grpc_service.proto envoy/api/v2/core/health_check.proto envoy/api/v2/core/http_uri.proto +envoy/api/v2/core/protocol.proto envoy/api/v2/discovery.proto envoy/api/v2/eds.proto envoy/api/v2/endpoint/endpoint.proto envoy/api/v2/endpoint/load_report.proto +envoy/api/v2/lds.proto +envoy/api/v2/listener/listener.proto +envoy/api/v2/listener/udp_listener_config.proto +envoy/api/v2/rds.proto +envoy/api/v2/route/route.proto +envoy/config/listener/v2/api_listener.proto envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto +envoy/type/matcher/regex.proto +envoy/type/matcher/string.proto envoy/type/percent.proto envoy/type/range.proto ) diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/cds.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cds.proto new file mode 100644 index 00000000000..cbd0eea5de4 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cds.proto @@ -0,0 +1,830 @@ +syntax = "proto3"; + +package envoy.api.v2; + +option java_outer_classname = "CdsProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2"; +option java_generic_services = true; + +import "envoy/api/v2/auth/cert.proto"; +import "envoy/api/v2/cluster/circuit_breaker.proto"; +import "envoy/api/v2/cluster/filter.proto"; +import "envoy/api/v2/cluster/outlier_detection.proto"; +import "envoy/api/v2/core/address.proto"; +import "envoy/api/v2/core/base.proto"; +import "envoy/api/v2/core/config_source.proto"; +import "envoy/api/v2/core/health_check.proto"; +import "envoy/api/v2/core/protocol.proto"; +import "envoy/api/v2/discovery.proto"; +import "envoy/api/v2/eds.proto"; +import "envoy/type/percent.proto"; + +import "google/api/annotations.proto"; +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Clusters] + +// Return list of all clusters this proxy will load balance to. +service ClusterDiscoveryService { + rpc StreamClusters(stream DiscoveryRequest) returns (stream DiscoveryResponse) { + } + + rpc DeltaClusters(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) { + } + + rpc FetchClusters(DiscoveryRequest) returns (DiscoveryResponse) { + option (google.api.http) = { + post: "/v2/discovery:clusters" + body: "*" + }; + } +} + +// Configuration for a single upstream cluster. +// [#comment:next free field: 45] +message Cluster { + // Refer to :ref:`service discovery type ` + // for an explanation on each type. + enum DiscoveryType { + // Refer to the :ref:`static discovery type` + // for an explanation. + STATIC = 0; + + // Refer to the :ref:`strict DNS discovery + // type` + // for an explanation. + STRICT_DNS = 1; + + // Refer to the :ref:`logical DNS discovery + // type` + // for an explanation. + LOGICAL_DNS = 2; + + // Refer to the :ref:`service discovery type` + // for an explanation. + EDS = 3; + + // Refer to the :ref:`original destination discovery + // type` + // for an explanation. + ORIGINAL_DST = 4; + } + + // Refer to :ref:`load balancer type ` architecture + // overview section for information on each type. + enum LbPolicy { + // Refer to the :ref:`round robin load balancing + // policy` + // for an explanation. + ROUND_ROBIN = 0; + + // Refer to the :ref:`least request load balancing + // policy` + // for an explanation. + LEAST_REQUEST = 1; + + // Refer to the :ref:`ring hash load balancing + // policy` + // for an explanation. + RING_HASH = 2; + + // Refer to the :ref:`random load balancing + // policy` + // for an explanation. + RANDOM = 3; + + // Refer to the :ref:`original destination load balancing + // policy` + // for an explanation. + // + // .. attention:: + // + // **This load balancing policy is deprecated**. Use CLUSTER_PROVIDED instead. + // + ORIGINAL_DST_LB = 4 [deprecated = true]; + + // Refer to the :ref:`Maglev load balancing policy` + // for an explanation. + MAGLEV = 5; + + // This load balancer type must be specified if the configured cluster provides a cluster + // specific load balancer. Consult the configured cluster's documentation for whether to set + // this option or not. + CLUSTER_PROVIDED = 6; + + // [#not-implemented-hide:] Use the new :ref:`load_balancing_policy + // ` field to determine the LB policy. + // [#next-major-version: In the v3 API, we should consider deprecating the lb_policy field + // and instead using the new load_balancing_policy field as the one and only mechanism for + // configuring this.] + LOAD_BALANCING_POLICY_CONFIG = 7; + } + + // When V4_ONLY is selected, the DNS resolver will only perform a lookup for + // addresses in the IPv4 family. If V6_ONLY is selected, the DNS resolver will + // only perform a lookup for addresses in the IPv6 family. If AUTO is + // specified, the DNS resolver will first perform a lookup for addresses in + // the IPv6 family and fallback to a lookup for addresses in the IPv4 family. + // For cluster types other than + // :ref:`STRICT_DNS` and + // :ref:`LOGICAL_DNS`, + // this setting is + // ignored. + enum DnsLookupFamily { + AUTO = 0; + V4_ONLY = 1; + V6_ONLY = 2; + } + + enum ClusterProtocolSelection { + // Cluster can only operate on one of the possible upstream protocols (HTTP1.1, HTTP2). + // If :ref:`http2_protocol_options ` are + // present, HTTP2 will be used, otherwise HTTP1.1 will be used. + USE_CONFIGURED_PROTOCOL = 0; + + // Use HTTP1.1 or HTTP2, depending on which one is used on the downstream connection. + USE_DOWNSTREAM_PROTOCOL = 1; + } + + // TransportSocketMatch specifies what transport socket config will be used + // when the match conditions are satisfied. + message TransportSocketMatch { + // The name of the match, used in stats generation. + string name = 1 [(validate.rules).string = {min_len: 1}]; + + // Optional endpoint metadata match criteria. + // The connection to the endpoint with metadata matching what is set in this field + // will use the transport socket configuration specified here. + // The endpoint's metadata entry in *envoy.transport_socket* is used to match + // against the values specified in this field. + google.protobuf.Struct match = 2; + + // The configuration of the transport socket. + core.TransportSocket transport_socket = 3; + } + + // Extended cluster type. + message CustomClusterType { + // The type of the cluster to instantiate. The name must match a supported cluster type. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Cluster specific configuration which depends on the cluster being instantiated. + // See the supported cluster for further documentation. + google.protobuf.Any typed_config = 2; + } + + // Only valid when discovery type is EDS. + message EdsClusterConfig { + // Configuration for the source of EDS updates for this Cluster. + core.ConfigSource eds_config = 1; + + // Optional alternative to cluster name to present to EDS. This does not + // have the same restrictions as cluster name, i.e. it may be arbitrary + // length. + string service_name = 2; + } + + // Optionally divide the endpoints in this cluster into subsets defined by + // endpoint metadata and selected by route and weighted cluster metadata. + message LbSubsetConfig { + // If NO_FALLBACK is selected, a result + // equivalent to no healthy hosts is reported. If ANY_ENDPOINT is selected, + // any cluster endpoint may be returned (subject to policy, health checks, + // etc). If DEFAULT_SUBSET is selected, load balancing is performed over the + // endpoints matching the values from the default_subset field. + enum LbSubsetFallbackPolicy { + NO_FALLBACK = 0; + ANY_ENDPOINT = 1; + DEFAULT_SUBSET = 2; + } + + // Specifications for subsets. + message LbSubsetSelector { + // Allows to override top level fallback policy per selector. + enum LbSubsetSelectorFallbackPolicy { + // If NOT_DEFINED top level config fallback policy is used instead. + NOT_DEFINED = 0; + + // If NO_FALLBACK is selected, a result equivalent to no healthy hosts is reported. + NO_FALLBACK = 1; + + // If ANY_ENDPOINT is selected, any cluster endpoint may be returned + // (subject to policy, health checks, etc). + ANY_ENDPOINT = 2; + + // If DEFAULT_SUBSET is selected, load balancing is performed over the + // endpoints matching the values from the default_subset field. + DEFAULT_SUBSET = 3; + } + + // List of keys to match with the weighted cluster metadata. + repeated string keys = 1; + + // The behavior used when no endpoint subset matches the selected route's + // metadata. + LbSubsetSelectorFallbackPolicy fallback_policy = 2 + [(validate.rules).enum = {defined_only: true}]; + } + + // The behavior used when no endpoint subset matches the selected route's + // metadata. The value defaults to + // :ref:`NO_FALLBACK`. + LbSubsetFallbackPolicy fallback_policy = 1 [(validate.rules).enum = {defined_only: true}]; + + // Specifies the default subset of endpoints used during fallback if + // fallback_policy is + // :ref:`DEFAULT_SUBSET`. + // Each field in default_subset is + // compared to the matching LbEndpoint.Metadata under the *envoy.lb* + // namespace. It is valid for no hosts to match, in which case the behavior + // is the same as a fallback_policy of + // :ref:`NO_FALLBACK`. + google.protobuf.Struct default_subset = 2; + + // For each entry, LbEndpoint.Metadata's + // *envoy.lb* namespace is traversed and a subset is created for each unique + // combination of key and value. For example: + // + // .. code-block:: json + // + // { "subset_selectors": [ + // { "keys": [ "version" ] }, + // { "keys": [ "stage", "hardware_type" ] } + // ]} + // + // A subset is matched when the metadata from the selected route and + // weighted cluster contains the same keys and values as the subset's + // metadata. The same host may appear in multiple subsets. + repeated LbSubsetSelector subset_selectors = 3; + + // If true, routing to subsets will take into account the localities and locality weights of the + // endpoints when making the routing decision. + // + // There are some potential pitfalls associated with enabling this feature, as the resulting + // traffic split after applying both a subset match and locality weights might be undesirable. + // + // Consider for example a situation in which you have 50/50 split across two localities X/Y + // which have 100 hosts each without subsetting. If the subset LB results in X having only 1 + // host selected but Y having 100, then a lot more load is being dumped on the single host in X + // than originally anticipated in the load balancing assignment delivered via EDS. + bool locality_weight_aware = 4; + + // When used with locality_weight_aware, scales the weight of each locality by the ratio + // of hosts in the subset vs hosts in the original subset. This aims to even out the load + // going to an individual locality if said locality is disproportionally affected by the + // subset predicate. + bool scale_locality_weight = 5; + + // If true, when a fallback policy is configured and its corresponding subset fails to find + // a host this will cause any host to be selected instead. + // + // This is useful when using the default subset as the fallback policy, given the default + // subset might become empty. With this option enabled, if that happens the LB will attempt + // to select a host from the entire cluster. + bool panic_mode_any = 6; + + // If true, metadata specified for a metadata key will be matched against the corresponding + // endpoint metadata if the endpoint metadata matches the value exactly OR it is a list value + // and any of the elements in the list matches the criteria. + bool list_as_any = 7; + } + + // Specific configuration for the LeastRequest load balancing policy. + message LeastRequestLbConfig { + // The number of random healthy hosts from which the host with the fewest active requests will + // be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. + google.protobuf.UInt32Value choice_count = 1 [(validate.rules).uint32 = {gte: 2}]; + } + + // Specific configuration for the :ref:`RingHash` + // load balancing policy. + message RingHashLbConfig { + // The hash function used to hash hosts onto the ketama ring. + enum HashFunction { + // Use `xxHash `_, this is the default hash function. + XX_HASH = 0; + + // Use `MurmurHash2 `_, this is compatible with + // std:hash in GNU libstdc++ 3.4.20 or above. This is typically the case when compiled + // on Linux and not macOS. + MURMUR_HASH_2 = 1; + } + + reserved 2; + + // Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each + // provided host) the better the request distribution will reflect the desired weights. Defaults + // to 1024 entries, and limited to 8M entries. See also + // :ref:`maximum_ring_size`. + google.protobuf.UInt64Value minimum_ring_size = 1 [(validate.rules).uint64 = {lte: 8388608}]; + + // The hash function used to hash hosts onto the ketama ring. The value defaults to + // :ref:`XX_HASH`. + HashFunction hash_function = 3 [(validate.rules).enum = {defined_only: true}]; + + // Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered + // to further constrain resource use. See also + // :ref:`minimum_ring_size`. + google.protobuf.UInt64Value maximum_ring_size = 4 [(validate.rules).uint64 = {lte: 8388608}]; + } + + // Specific configuration for the + // :ref:`Original Destination ` + // load balancing policy. + message OriginalDstLbConfig { + // When true, :ref:`x-envoy-original-dst-host + // ` can be used to override destination + // address. + // + // .. attention:: + // + // This header isn't sanitized by default, so enabling this feature allows HTTP clients to + // route traffic to arbitrary hosts and/or ports, which may have serious security + // consequences. + bool use_http_header = 1; + } + + // Common configuration for all load balancer implementations. + message CommonLbConfig { + // Configuration for :ref:`zone aware routing + // `. + message ZoneAwareLbConfig { + // Configures percentage of requests that will be considered for zone aware routing + // if zone aware routing is configured. If not specified, the default is 100%. + // * :ref:`runtime values `. + // * :ref:`Zone aware routing support `. + type.Percent routing_enabled = 1; + + // Configures minimum upstream cluster size required for zone aware routing + // If upstream cluster size is less than specified, zone aware routing is not performed + // even if zone aware routing is configured. If not specified, the default is 6. + // * :ref:`runtime values `. + // * :ref:`Zone aware routing support `. + google.protobuf.UInt64Value min_cluster_size = 2; + + // If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic + // mode`. Instead, the cluster will fail all + // requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a + // failing service. + bool fail_traffic_on_panic = 3; + } + + // Configuration for :ref:`locality weighted load balancing + // ` + message LocalityWeightedLbConfig { + } + + // Configures the :ref:`healthy panic threshold `. + // If not specified, the default is 50%. + // To disable panic mode, set to 0%. + // + // .. note:: + // The specified percent will be truncated to the nearest 1%. + type.Percent healthy_panic_threshold = 1; + + oneof locality_config_specifier { + ZoneAwareLbConfig zone_aware_lb_config = 2; + + LocalityWeightedLbConfig locality_weighted_lb_config = 3; + } + + // If set, all health check/weight/metadata updates that happen within this duration will be + // merged and delivered in one shot when the duration expires. The start of the duration is when + // the first update happens. This is useful for big clusters, with potentially noisy deploys + // that might trigger excessive CPU usage due to a constant stream of healthcheck state changes + // or metadata updates. The first set of updates to be seen apply immediately (e.g.: a new + // cluster). Please always keep in mind that the use of sandbox technologies may change this + // behavior. + // + // If this is not set, we default to a merge window of 1000ms. To disable it, set the merge + // window to 0. + // + // Note: merging does not apply to cluster membership changes (e.g.: adds/removes); this is + // because merging those updates isn't currently safe. See + // https://github.com/envoyproxy/envoy/pull/3941. + google.protobuf.Duration update_merge_window = 4; + + // If set to true, Envoy will not consider new hosts when computing load balancing weights until + // they have been health checked for the first time. This will have no effect unless + // active health checking is also configured. + // + // Ignoring a host means that for any load balancing calculations that adjust weights based + // on the ratio of eligible hosts and total hosts (priority spillover, locality weighting and + // panic mode) Envoy will exclude these hosts in the denominator. + // + // For example, with hosts in two priorities P0 and P1, where P0 looks like + // {healthy, unhealthy (new), unhealthy (new)} + // and where P1 looks like + // {healthy, healthy} + // all traffic will still hit P0, as 1 / (3 - 2) = 1. + // + // Enabling this will allow scaling up the number of hosts for a given cluster without entering + // panic mode or triggering priority spillover, assuming the hosts pass the first health check. + // + // If panic mode is triggered, new hosts are still eligible for traffic; they simply do not + // contribute to the calculation when deciding whether panic mode is enabled or not. + bool ignore_new_hosts_until_first_hc = 5; + + // If set to `true`, the cluster manager will drain all existing + // connections to upstream hosts whenever hosts are added or removed from the cluster. + bool close_connections_on_host_set_change = 6; + } + + message RefreshRate { + // Specifies the base interval between refreshes. This parameter is required and must be greater + // than zero and less than + // :ref:`max_interval `. + google.protobuf.Duration base_interval = 1 [(validate.rules).duration = { + required: true + gt {nanos: 1000000} + }]; + + // Specifies the maximum interval between refreshes. This parameter is optional, but must be + // greater than or equal to the + // :ref:`base_interval ` if set. The default + // is 10 times the :ref:`base_interval `. + google.protobuf.Duration max_interval = 2 [(validate.rules).duration = {gt {nanos: 1000000}}]; + } + + reserved 12, 15; + + // Configuration to use different transport sockets for different endpoints. + // The entry of *envoy.transport_socket* in the + // :ref:`LbEndpoint.Metadata ` + // is used to match against the transport sockets as they appear in the list. The first + // :ref:`match ` is used. + // For example, with the following match + // + // .. code-block:: yaml + // + // transport_socket_matches: + // - name: "enableMTLS" + // match: + // acceptMTLS: true + // transport_socket: + // name: tls + // config: { ... } # tls socket configuration + // - name: "defaultToPlaintext" + // match: {} + // transport_socket: + // name: "rawbuffer" + // + // Connections to the endpoints whose metadata value under *envoy.transport_socket* + // having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. + // + // If a :ref:`socket match ` with empty match + // criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" + // socket match in case above. + // + // If an endpoint metadata's value under *envoy.transport_socket* does not match any + // *TransportSocketMatch*, socket configuration fallbacks to use the *tls_context* or + // *transport_socket* specified in this cluster. + // + // This field allows gradual and flexible transport socket configuration changes. + // + // The metadata of endpoints in EDS can indicate transport socket capabilities. For example, + // an endpoint's metadata can have two key value pairs as "acceptMTLS": "true", + // "acceptPlaintext": "true". While some other endpoints, only accepting plaintext traffic + // has "acceptPlaintext": "true" metadata information. + // + // Then the xDS server can configure the CDS to a client, Envoy A, to send mutual TLS + // traffic for endpoints with "acceptMTLS": "true", by adding a corresponding + // *TransportSocketMatch* in this field. Other client Envoys receive CDS without + // *transport_socket_match* set, and still send plain text traffic to the same cluster. + // + // TODO(incfly): add a detailed architecture doc on intended usage. + // [#not-implemented-hide:] + repeated TransportSocketMatch transport_socket_matches = 43; + + // Supplies the name of the cluster which must be unique across all clusters. + // The cluster name is used when emitting + // :ref:`statistics ` if :ref:`alt_stat_name + // ` is not provided. + // Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // An optional alternative to the cluster name to be used while emitting stats. + // Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be + // confused with :ref:`Router Filter Header + // `. + string alt_stat_name = 28; + + oneof cluster_discovery_type { + // The :ref:`service discovery type ` + // to use for resolving the cluster. + DiscoveryType type = 2 [(validate.rules).enum = {defined_only: true}]; + + // The custom cluster type. + CustomClusterType cluster_type = 38; + } + + // Configuration to use for EDS updates for the Cluster. + EdsClusterConfig eds_cluster_config = 3; + + // The timeout for new network connections to hosts in the cluster. + google.protobuf.Duration connect_timeout = 4 [(validate.rules).duration = {gt {}}]; + + // Soft limit on size of the cluster’s connections read and write buffers. If + // unspecified, an implementation defined default is applied (1MiB). + google.protobuf.UInt32Value per_connection_buffer_limit_bytes = 5; + + // The :ref:`load balancer type ` to use + // when picking a host in the cluster. + LbPolicy lb_policy = 6 [(validate.rules).enum = {defined_only: true}]; + + // If the service discovery type is + // :ref:`STATIC`, + // :ref:`STRICT_DNS` + // or :ref:`LOGICAL_DNS`, + // then hosts is required. + // + // .. attention:: + // + // **This field is deprecated**. Set the + // :ref:`load_assignment` field instead. + // + repeated core.Address hosts = 7; + + // Setting this is required for specifying members of + // :ref:`STATIC`, + // :ref:`STRICT_DNS` + // or :ref:`LOGICAL_DNS` clusters. + // This field supersedes :ref:`hosts` field. + // [#comment:TODO(dio): Deprecate the hosts field and add it to :ref:`deprecated log` + // once load_assignment is implemented.] + // + // .. attention:: + // + // Setting this allows non-EDS cluster types to contain embedded EDS equivalent + // :ref:`endpoint assignments`. + // Setting this overrides :ref:`hosts` values. + // + ClusterLoadAssignment load_assignment = 33; + + // Optional :ref:`active health checking ` + // configuration for the cluster. If no + // configuration is specified no health checking will be done and all cluster + // members will be considered healthy at all times. + repeated core.HealthCheck health_checks = 8; + + // Optional maximum requests for a single upstream connection. This parameter + // is respected by both the HTTP/1.1 and HTTP/2 connection pool + // implementations. If not specified, there is no limit. Setting this + // parameter to 1 will effectively disable keep alive. + google.protobuf.UInt32Value max_requests_per_connection = 9; + + // Optional :ref:`circuit breaking ` for the cluster. + cluster.CircuitBreakers circuit_breakers = 10; + + // The TLS configuration for connections to the upstream cluster. If no TLS + // configuration is specified, TLS will not be used for new connections. + // + // .. attention:: + // + // Server certificate verification is not enabled by default. Configure + // :ref:`trusted_ca` to enable + // verification. + auth.UpstreamTlsContext tls_context = 11; + + // Additional options when handling HTTP requests. These options will be applicable to both + // HTTP1 and HTTP2 requests. + core.HttpProtocolOptions common_http_protocol_options = 29; + + // Additional options when handling HTTP1 requests. + core.Http1ProtocolOptions http_protocol_options = 13; + + // Even if default HTTP2 protocol options are desired, this field must be + // set so that Envoy will assume that the upstream supports HTTP/2 when + // making new HTTP connection pool connections. Currently, Envoy only + // supports prior knowledge for upstream connections. Even if TLS is used + // with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 + // connections to happen over plain text. + core.Http2ProtocolOptions http2_protocol_options = 14; + + // The extension_protocol_options field is used to provide extension-specific protocol options + // for upstream connections. The key should match the extension filter name, such as + // "envoy.filters.network.thrift_proxy". See the extension's documentation for details on + // specific options. + map extension_protocol_options = 35; + + // The extension_protocol_options field is used to provide extension-specific protocol options + // for upstream connections. The key should match the extension filter name, such as + // "envoy.filters.network.thrift_proxy". See the extension's documentation for details on + // specific options. + map typed_extension_protocol_options = 36; + + // If the DNS refresh rate is specified and the cluster type is either + // :ref:`STRICT_DNS`, + // or :ref:`LOGICAL_DNS`, + // this value is used as the cluster’s DNS refresh + // rate. If this setting is not specified, the value defaults to 5000ms. For + // cluster types other than + // :ref:`STRICT_DNS` + // and :ref:`LOGICAL_DNS` + // this setting is ignored. + google.protobuf.Duration dns_refresh_rate = 16 [(validate.rules).duration = {gt {}}]; + + // If the DNS failure refresh rate is specified and the cluster type is either + // :ref:`STRICT_DNS`, + // or :ref:`LOGICAL_DNS`, + // this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is + // not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types + // other than :ref:`STRICT_DNS` and + // :ref:`LOGICAL_DNS` this setting is + // ignored. + // + // Note: Currently, DNS failures and empty DNS responses are not treated differently and this + // configuration is applied in both situations. + RefreshRate dns_failure_refresh_rate = 44; + + // Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, + // cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS + // resolution. + bool respect_dns_ttl = 39; + + // The DNS IP address resolution policy. If this setting is not specified, the + // value defaults to + // :ref:`AUTO`. + DnsLookupFamily dns_lookup_family = 17 [(validate.rules).enum = {defined_only: true}]; + + // If DNS resolvers are specified and the cluster type is either + // :ref:`STRICT_DNS`, + // or :ref:`LOGICAL_DNS`, + // this value is used to specify the cluster’s dns resolvers. + // If this setting is not specified, the value defaults to the default + // resolver, which uses /etc/resolv.conf for configuration. For cluster types + // other than + // :ref:`STRICT_DNS` + // and :ref:`LOGICAL_DNS` + // this setting is ignored. + repeated core.Address dns_resolvers = 18; + + // If specified, outlier detection will be enabled for this upstream cluster. + // Each of the configuration values can be overridden via + // :ref:`runtime values `. + cluster.OutlierDetection outlier_detection = 19; + + // The interval for removing stale hosts from a cluster type + // :ref:`ORIGINAL_DST`. + // Hosts are considered stale if they have not been used + // as upstream destinations during this interval. New hosts are added + // to original destination clusters on demand as new connections are + // redirected to Envoy, causing the number of hosts in the cluster to + // grow over time. Hosts that are not stale (they are actively used as + // destinations) are kept in the cluster, which allows connections to + // them remain open, saving the latency that would otherwise be spent + // on opening new connections. If this setting is not specified, the + // value defaults to 5000ms. For cluster types other than + // :ref:`ORIGINAL_DST` + // this setting is ignored. + google.protobuf.Duration cleanup_interval = 20 [(validate.rules).duration = {gt {}}]; + + // Optional configuration used to bind newly established upstream connections. + // This overrides any bind_config specified in the bootstrap proto. + // If the address and port are empty, no bind will be performed. + core.BindConfig upstream_bind_config = 21; + + // Configuration for load balancing subsetting. + LbSubsetConfig lb_subset_config = 22; + + // Optional configuration for the load balancing algorithm selected by + // LbPolicy. Currently only + // :ref:`RING_HASH` and + // :ref:`LEAST_REQUEST` + // has additional configuration options. + // Specifying ring_hash_lb_config or least_request_lb_config without setting the corresponding + // LbPolicy will generate an error at runtime. + oneof lb_config { + // Optional configuration for the Ring Hash load balancing policy. + RingHashLbConfig ring_hash_lb_config = 23; + + // Optional configuration for the Original Destination load balancing policy. + OriginalDstLbConfig original_dst_lb_config = 34; + + // Optional configuration for the LeastRequest load balancing policy. + LeastRequestLbConfig least_request_lb_config = 37; + } + + // Common configuration for all load balancer implementations. + CommonLbConfig common_lb_config = 27; + + // Optional custom transport socket implementation to use for upstream connections. + core.TransportSocket transport_socket = 24; + + // The Metadata field can be used to provide additional information about the + // cluster. It can be used for stats, logging, and varying filter behavior. + // Fields should use reverse DNS notation to denote which entity within Envoy + // will need the information. For instance, if the metadata is intended for + // the Router filter, the filter name should be specified as *envoy.router*. + core.Metadata metadata = 25; + + // Determines how Envoy selects the protocol used to speak to upstream hosts. + ClusterProtocolSelection protocol_selection = 26; + + // Optional options for upstream connections. + UpstreamConnectionOptions upstream_connection_options = 30; + + // If an upstream host becomes unhealthy (as determined by the configured health checks + // or outlier detection), immediately close all connections to the failed host. + // + // .. note:: + // + // This is currently only supported for connections created by tcp_proxy. + // + // .. note:: + // + // The current implementation of this feature closes all connections immediately when + // the unhealthy status is detected. If there are a large number of connections open + // to an upstream host that becomes unhealthy, Envoy may spend a substantial amount of + // time exclusively closing these connections, and not processing any other traffic. + bool close_connections_on_host_health_failure = 31; + + // If this cluster uses EDS or STRICT_DNS to configure its hosts, immediately drain + // connections from any hosts that are removed from service discovery. + // + // This only affects behavior for hosts that are being actively health checked. + // If this flag is not set to true, Envoy will wait until the hosts fail active health + // checking before removing it from the cluster. + bool drain_connections_on_host_removal = 32; + + // An (optional) network filter chain, listed in the order the filters should be applied. + // The chain will be applied to all outgoing connections that Envoy makes to the upstream + // servers of this cluster. + repeated cluster.Filter filters = 40; + + // [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the + // :ref:`lb_policy` field has the value + // :ref:`LOAD_BALANCING_POLICY_CONFIG`. + LoadBalancingPolicy load_balancing_policy = 41; + + // [#not-implemented-hide:] + // If present, tells the client where to send load reports via LRS. If not present, the + // client will fall back to a client-side default, which may be either (a) don't send any + // load reports or (b) send load reports for all clusters to a single default server + // (which may be configured in the bootstrap file). + // + // Note that if multiple clusters point to the same LRS server, the client may choose to + // create a separate stream for each cluster or it may choose to coalesce the data for + // multiple clusters onto a single stream. Either way, the client must make sure to send + // the data for any given cluster on no more than one stream. + // + // [#next-major-version: In the v3 API, we should consider restructuring this somehow, + // maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation + // from the LRS stream here.] + core.ConfigSource lrs_server = 42; +} + +// [#not-implemented-hide:] Extensible load balancing policy configuration. +// +// Every LB policy defined via this mechanism will be identified via a unique name using reverse +// DNS notation. If the policy needs configuration parameters, it must define a message for its +// own configuration, which will be stored in the config field. The name of the policy will tell +// clients which type of message they should expect to see in the config field. +// +// Note that there are cases where it is useful to be able to independently select LB policies +// for choosing a locality and for choosing an endpoint within that locality. For example, a +// given deployment may always use the same policy to choose the locality, but for choosing the +// endpoint within the locality, some clusters may use weighted-round-robin, while others may +// use some sort of session-based balancing. +// +// This can be accomplished via hierarchical LB policies, where the parent LB policy creates a +// child LB policy for each locality. For each request, the parent chooses the locality and then +// delegates to the child policy for that locality to choose the endpoint within the locality. +// +// To facilitate this, the config message for the top-level LB policy may include a field of +// type LoadBalancingPolicy that specifies the child policy. +message LoadBalancingPolicy { + message Policy { + // Required. The name of the LB policy. + string name = 1; + + // Optional config for the LB policy. + // No more than one of these two fields may be populated. + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } + + // Each client will iterate over the list in order and stop at the first policy that it + // supports. This provides a mechanism for starting to use new LB policies that are not yet + // supported by all clients. + repeated Policy policies = 1; +} + +// An extensible structure containing the address Envoy should bind to when +// establishing upstream connections. +message UpstreamBindConfig { + // The address Envoy should bind to when establishing upstream connections. + core.Address source_address = 1; +} + +message UpstreamConnectionOptions { + // If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. + core.TcpKeepalive tcp_keepalive = 1; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/circuit_breaker.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/circuit_breaker.proto new file mode 100644 index 00000000000..d2e0a328e49 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/circuit_breaker.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; + +package envoy.api.v2.cluster; + +option java_outer_classname = "CircuitBreakerProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.cluster"; +option csharp_namespace = "Envoy.Api.V2.ClusterNS"; +option ruby_package = "Envoy.Api.V2.ClusterNS"; + +import "envoy/api/v2/core/base.proto"; + +import "google/protobuf/wrappers.proto"; + +// [#protodoc-title: Circuit breakers] + +// :ref:`Circuit breaking` settings can be +// specified individually for each defined priority. +message CircuitBreakers { + // A Thresholds defines CircuitBreaker settings for a + // :ref:`RoutingPriority`. + message Thresholds { + // The :ref:`RoutingPriority` + // the specified CircuitBreaker settings apply to. + // [#comment:TODO(htuch): add (validate.rules).enum.defined_only = true once + // https://github.com/lyft/protoc-gen-validate/issues/42 is resolved.] + core.RoutingPriority priority = 1; + + // The maximum number of connections that Envoy will make to the upstream + // cluster. If not specified, the default is 1024. + google.protobuf.UInt32Value max_connections = 2; + + // The maximum number of pending requests that Envoy will allow to the + // upstream cluster. If not specified, the default is 1024. + google.protobuf.UInt32Value max_pending_requests = 3; + + // The maximum number of parallel requests that Envoy will make to the + // upstream cluster. If not specified, the default is 1024. + google.protobuf.UInt32Value max_requests = 4; + + // The maximum number of parallel retries that Envoy will allow to the + // upstream cluster. If not specified, the default is 3. + google.protobuf.UInt32Value max_retries = 5; + + // If track_remaining is true, then stats will be published that expose + // the number of resources remaining until the circuit breakers open. If + // not specified, the default is false. + bool track_remaining = 6; + + // The maximum number of connection pools per cluster that Envoy will concurrently support at + // once. If not specified, the default is unlimited. Set this for clusters which create a + // large number of connection pools. See + // :ref:`Circuit Breaking ` for + // more details. + google.protobuf.UInt32Value max_connection_pools = 7; + } + + // If multiple :ref:`Thresholds` + // are defined with the same :ref:`RoutingPriority`, + // the first one in the list is used. If no Thresholds is defined for a given + // :ref:`RoutingPriority`, the default values + // are used. + repeated Thresholds thresholds = 1; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/filter.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/filter.proto new file mode 100644 index 00000000000..b89b2a6b778 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/filter.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package envoy.api.v2.cluster; + +option java_outer_classname = "FilterProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.cluster"; +option csharp_namespace = "Envoy.Api.V2.ClusterNS"; +option ruby_package = "Envoy.Api.V2.ClusterNS"; + +import "google/protobuf/any.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Upstream filters] +// +// Upstream filters apply to the connections to the upstream cluster hosts. +message Filter { + // The name of the filter to instantiate. The name must match a + // :ref:`supported filter `. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Filter specific configuration which depends on the filter being + // instantiated. See the supported filters for further documentation. + google.protobuf.Any typed_config = 2; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/outlier_detection.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/outlier_detection.proto new file mode 100644 index 00000000000..4702bd0a6f1 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/cluster/outlier_detection.proto @@ -0,0 +1,146 @@ +syntax = "proto3"; + +package envoy.api.v2.cluster; + +option java_outer_classname = "OutlierDetectionProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.cluster"; +option csharp_namespace = "Envoy.Api.V2.ClusterNS"; +option ruby_package = "Envoy.Api.V2.ClusterNS"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Outlier detection] + +// See the :ref:`architecture overview ` for +// more information on outlier detection. +message OutlierDetection { + // The number of consecutive 5xx responses or local origin errors that are mapped + // to 5xx error codes before a consecutive 5xx ejection + // occurs. Defaults to 5. + google.protobuf.UInt32Value consecutive_5xx = 1; + + // The time interval between ejection analysis sweeps. This can result in + // both new ejections as well as hosts being returned to service. Defaults + // to 10000ms or 10s. + google.protobuf.Duration interval = 2 [(validate.rules).duration = {gt {}}]; + + // The base time that a host is ejected for. The real time is equal to the + // base time multiplied by the number of times the host has been ejected. + // Defaults to 30000ms or 30s. + google.protobuf.Duration base_ejection_time = 3 [(validate.rules).duration = {gt {}}]; + + // The maximum % of an upstream cluster that can be ejected due to outlier + // detection. Defaults to 10% but will eject at least one host regardless of the value. + google.protobuf.UInt32Value max_ejection_percent = 4 [(validate.rules).uint32 = {lte: 100}]; + + // The % chance that a host will be actually ejected when an outlier status + // is detected through consecutive 5xx. This setting can be used to disable + // ejection or to ramp it up slowly. Defaults to 100. + google.protobuf.UInt32Value enforcing_consecutive_5xx = 5 [(validate.rules).uint32 = {lte: 100}]; + + // The % chance that a host will be actually ejected when an outlier status + // is detected through success rate statistics. This setting can be used to + // disable ejection or to ramp it up slowly. Defaults to 100. + google.protobuf.UInt32Value enforcing_success_rate = 6 [(validate.rules).uint32 = {lte: 100}]; + + // The number of hosts in a cluster that must have enough request volume to + // detect success rate outliers. If the number of hosts is less than this + // setting, outlier detection via success rate statistics is not performed + // for any host in the cluster. Defaults to 5. + google.protobuf.UInt32Value success_rate_minimum_hosts = 7; + + // The minimum number of total requests that must be collected in one + // interval (as defined by the interval duration above) to include this host + // in success rate based outlier detection. If the volume is lower than this + // setting, outlier detection via success rate statistics is not performed + // for that host. Defaults to 100. + google.protobuf.UInt32Value success_rate_request_volume = 8; + + // This factor is used to determine the ejection threshold for success rate + // outlier ejection. The ejection threshold is the difference between the + // mean success rate, and the product of this factor and the standard + // deviation of the mean success rate: mean - (stdev * + // success_rate_stdev_factor). This factor is divided by a thousand to get a + // double. That is, if the desired factor is 1.9, the runtime value should + // be 1900. Defaults to 1900. + google.protobuf.UInt32Value success_rate_stdev_factor = 9; + + // The number of consecutive gateway failures (502, 503, 504 status codes) + // before a consecutive gateway failure ejection occurs. Defaults to 5. + google.protobuf.UInt32Value consecutive_gateway_failure = 10; + + // The % chance that a host will be actually ejected when an outlier status + // is detected through consecutive gateway failures. This setting can be + // used to disable ejection or to ramp it up slowly. Defaults to 0. + google.protobuf.UInt32Value enforcing_consecutive_gateway_failure = 11 + [(validate.rules).uint32 = {lte: 100}]; + + // Determines whether to distinguish local origin failures from external errors. If set to true + // the following configuration parameters are taken into account: + // :ref:`consecutive_local_origin_failure`, + // :ref:`enforcing_consecutive_local_origin_failure` + // and + // :ref:`enforcing_local_origin_success_rate`. + // Defaults to false. + bool split_external_local_origin_errors = 12; + + // The number of consecutive locally originated failures before ejection + // occurs. Defaults to 5. Parameter takes effect only when + // :ref:`split_external_local_origin_errors` + // is set to true. + google.protobuf.UInt32Value consecutive_local_origin_failure = 13; + + // The % chance that a host will be actually ejected when an outlier status + // is detected through consecutive locally originated failures. This setting can be + // used to disable ejection or to ramp it up slowly. Defaults to 100. + // Parameter takes effect only when + // :ref:`split_external_local_origin_errors` + // is set to true. + google.protobuf.UInt32Value enforcing_consecutive_local_origin_failure = 14 + [(validate.rules).uint32 = {lte: 100}]; + + // The % chance that a host will be actually ejected when an outlier status + // is detected through success rate statistics for locally originated errors. + // This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. + // Parameter takes effect only when + // :ref:`split_external_local_origin_errors` + // is set to true. + google.protobuf.UInt32Value enforcing_local_origin_success_rate = 15 + [(validate.rules).uint32 = {lte: 100}]; + + // The failure percentage to use when determining failure percentage-based outlier detection. If + // the failure percentage of a given host is greater than or equal to this value, it will be + // ejected. Defaults to 85. + google.protobuf.UInt32Value failure_percentage_threshold = 16 + [(validate.rules).uint32 = {lte: 100}]; + + // The % chance that a host will be actually ejected when an outlier status is detected through + // failure percentage statistics. This setting can be used to disable ejection or to ramp it up + // slowly. Defaults to 0. + // + // [#next-major-version: setting this without setting failure_percentage_threshold should be + // invalid in v4.] + google.protobuf.UInt32Value enforcing_failure_percentage = 17 + [(validate.rules).uint32 = {lte: 100}]; + + // The % chance that a host will be actually ejected when an outlier status is detected through + // local-origin failure percentage statistics. This setting can be used to disable ejection or to + // ramp it up slowly. Defaults to 0. + google.protobuf.UInt32Value enforcing_failure_percentage_local_origin = 18 + [(validate.rules).uint32 = {lte: 100}]; + + // The minimum number of hosts in a cluster in order to perform failure percentage-based ejection. + // If the total number of hosts in the cluster is less than this value, failure percentage-based + // ejection will not be performed. Defaults to 5. + google.protobuf.UInt32Value failure_percentage_minimum_hosts = 19; + + // The minimum number of total requests that must be collected in one interval (as defined by the + // interval duration above) to perform failure percentage-based ejection for this host. If the + // volume is lower than this setting, failure percentage-based ejection will not be performed for + // this host. Defaults to 50. + google.protobuf.UInt32Value failure_percentage_request_volume = 20; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/protocol.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/protocol.proto new file mode 100644 index 00000000000..c45bb7adf7d --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/core/protocol.proto @@ -0,0 +1,152 @@ +syntax = "proto3"; + +package envoy.api.v2.core; + +option java_outer_classname = "ProtocolProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.core"; + +import "google/protobuf/duration.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Protocol options] + +// [#not-implemented-hide:] +message TcpProtocolOptions { +} + +message HttpProtocolOptions { + // The idle timeout for upstream connection pool connections. The idle timeout is defined as the + // period in which there are no active requests. If not set, there is no idle timeout. When the + // idle timeout is reached the connection will be closed. Note that request based timeouts mean + // that HTTP/2 PINGs will not keep the connection alive. + google.protobuf.Duration idle_timeout = 1; +} + +message Http1ProtocolOptions { + // Handle HTTP requests with absolute URLs in the requests. These requests + // are generally sent by clients to forward/explicit proxies. This allows clients to configure + // envoy as their HTTP proxy. In Unix, for example, this is typically done by setting the + // *http_proxy* environment variable. + google.protobuf.BoolValue allow_absolute_url = 1; + + // Handle incoming HTTP/1.0 and HTTP 0.9 requests. + // This is off by default, and not fully standards compliant. There is support for pre-HTTP/1.1 + // style connect logic, dechunking, and handling lack of client host iff + // *default_host_for_http_10* is configured. + bool accept_http_10 = 2; + + // A default host for HTTP/1.0 requests. This is highly suggested if *accept_http_10* is true as + // Envoy does not otherwise support HTTP/1.0 without a Host header. + // This is a no-op if *accept_http_10* is not true. + string default_host_for_http_10 = 3; +} + +// [#comment:next free field: 13] +message Http2ProtocolOptions { + // `Maximum table size `_ + // (in octets) that the encoder is permitted to use for the dynamic HPACK table. Valid values + // range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header + // compression. + google.protobuf.UInt32Value hpack_table_size = 1; + + // `Maximum concurrent streams `_ + // allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) + // and defaults to 2147483647. + google.protobuf.UInt32Value max_concurrent_streams = 2 + [(validate.rules).uint32 = {lte: 2147483647 gte: 1}]; + + // `Initial stream-level flow-control window + // `_ size. Valid values range from 65535 + // (2^16 - 1, HTTP/2 default) to 2147483647 (2^31 - 1, HTTP/2 maximum) and defaults to 268435456 + // (256 * 1024 * 1024). + // + // NOTE: 65535 is the initial window size from HTTP/2 spec. We only support increasing the default + // window size now, so it's also the minimum. + // + // This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the + // HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to + // stop the flow of data to the codec buffers. + google.protobuf.UInt32Value initial_stream_window_size = 3 + [(validate.rules).uint32 = {lte: 2147483647 gte: 65535}]; + + // Similar to *initial_stream_window_size*, but for connection-level flow-control + // window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. + google.protobuf.UInt32Value initial_connection_window_size = 4 + [(validate.rules).uint32 = {lte: 2147483647 gte: 65535}]; + + // Allows proxying Websocket and other upgrades over H2 connect. + bool allow_connect = 5; + + // [#not-implemented-hide:] Hiding until envoy has full metadata support. + // Still under implementation. DO NOT USE. + // + // Allows metadata. See [metadata + // docs](https://github.com/envoyproxy/envoy/blob/master/source/docs/h2_metadata.md) for more + // information. + bool allow_metadata = 6; + + // Limit the number of pending outbound downstream frames of all types (frames that are waiting to + // be written into the socket). Exceeding this limit triggers flood mitigation and connection is + // terminated. The ``http2.outbound_flood`` stat tracks the number of terminated connections due + // to flood mitigation. The default limit is 10000. + // [#comment:TODO: implement same limits for upstream outbound frames as well.] + google.protobuf.UInt32Value max_outbound_frames = 7 [(validate.rules).uint32 = {gte: 1}]; + + // Limit the number of pending outbound downstream frames of types PING, SETTINGS and RST_STREAM, + // preventing high memory utilization when receiving continuous stream of these frames. Exceeding + // this limit triggers flood mitigation and connection is terminated. The + // ``http2.outbound_control_flood`` stat tracks the number of terminated connections due to flood + // mitigation. The default limit is 1000. + // [#comment:TODO: implement same limits for upstream outbound frames as well.] + google.protobuf.UInt32Value max_outbound_control_frames = 8 [(validate.rules).uint32 = {gte: 1}]; + + // Limit the number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA with an + // empty payload and no end stream flag. Those frames have no legitimate use and are abusive, but + // might be a result of a broken HTTP/2 implementation. The `http2.inbound_empty_frames_flood`` + // stat tracks the number of connections terminated due to flood mitigation. + // Setting this to 0 will terminate connection upon receiving first frame with an empty payload + // and no end stream flag. The default limit is 1. + // [#comment:TODO: implement same limits for upstream inbound frames as well.] + google.protobuf.UInt32Value max_consecutive_inbound_frames_with_empty_payload = 9; + + // Limit the number of inbound PRIORITY frames allowed per each opened stream. If the number + // of PRIORITY frames received over the lifetime of connection exceeds the value calculated + // using this formula:: + // + // max_inbound_priority_frames_per_stream * (1 + inbound_streams) + // + // the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + // the number of connections terminated due to flood mitigation. The default limit is 100. + // [#comment:TODO: implement same limits for upstream inbound frames as well.] + google.protobuf.UInt32Value max_inbound_priority_frames_per_stream = 10; + + // Limit the number of inbound WINDOW_UPDATE frames allowed per DATA frame sent. If the number + // of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated + // using this formula:: + // + // 1 + 2 * (inbound_streams + + // max_inbound_window_update_frames_per_data_frame_sent * outbound_data_frames) + // + // the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + // the number of connections terminated due to flood mitigation. The default limit is 10. + // Setting this to 1 should be enough to support HTTP/2 implementations with basic flow control, + // but more complex implementations that try to estimate available bandwidth require at least 2. + // [#comment:TODO: implement same limits for upstream inbound frames as well.] + google.protobuf.UInt32Value max_inbound_window_update_frames_per_data_frame_sent = 11 + [(validate.rules).uint32 = {gte: 1}]; + + // Allows invalid HTTP messaging and headers. When this option is disabled (default), then + // the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, + // when this option is enabled, only the offending stream is terminated. + // + // See [RFC7540, sec. 8.1](https://tools.ietf.org/html/rfc7540#section-8.1) for details. + bool stream_error_on_invalid_http_messaging = 12; +} + +// [#not-implemented-hide:] +message GrpcProtocolOptions { + Http2ProtocolOptions http2_protocol_options = 1; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/lds.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/lds.proto new file mode 100644 index 00000000000..0ea940f6c47 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/lds.proto @@ -0,0 +1,217 @@ +syntax = "proto3"; + +package envoy.api.v2; + +option java_outer_classname = "LdsProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2"; +option java_generic_services = true; + +import "envoy/api/v2/core/address.proto"; +import "envoy/api/v2/core/base.proto"; +import "envoy/api/v2/discovery.proto"; +import "envoy/api/v2/listener/listener.proto"; +import "envoy/api/v2/listener/udp_listener_config.proto"; +import "envoy/config/listener/v2/api_listener.proto"; + +import "google/api/annotations.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Listener] +// Listener :ref:`configuration overview ` + +// The Envoy instance initiates an RPC at startup to discover a list of +// listeners. Updates are delivered via streaming from the LDS server and +// consist of a complete update of all listeners. Existing connections will be +// allowed to drain from listeners that are no longer present. +service ListenerDiscoveryService { + rpc DeltaListeners(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) { + } + + rpc StreamListeners(stream DiscoveryRequest) returns (stream DiscoveryResponse) { + } + + rpc FetchListeners(DiscoveryRequest) returns (DiscoveryResponse) { + option (google.api.http) = { + post: "/v2/discovery:listeners" + body: "*" + }; + } +} + +// [#comment:next free field: 20] +message Listener { + enum DrainType { + // Drain in response to calling /healthcheck/fail admin endpoint (along with the health check + // filter), listener removal/modification, and hot restart. + DEFAULT = 0; + + // Drain in response to listener removal/modification and hot restart. This setting does not + // include /healthcheck/fail. This setting may be desirable if Envoy is hosting both ingress + // and egress listeners. + MODIFY_ONLY = 1; + } + + // [#not-implemented-hide:] + message DeprecatedV1 { + // Whether the listener should bind to the port. A listener that doesn't + // bind can only receive connections redirected from other listeners that + // set use_original_dst parameter to true. Default is true. + // + // This is deprecated in v2, all Listeners will bind to their port. An + // additional filter chain must be created for every original destination + // port this listener may redirect to in v2, with the original port + // specified in the FilterChainMatch destination_port field. + // + // [#comment:TODO(PiotrSikora): Remove this once verified that we no longer need it.] + google.protobuf.BoolValue bind_to_port = 1; + } + + reserved 14; + + // The unique name by which this listener is known. If no name is provided, + // Envoy will allocate an internal UUID for the listener. If the listener is to be dynamically + // updated or removed via :ref:`LDS ` a unique name must be provided. + string name = 1; + + // The address that the listener should listen on. In general, the address must be unique, though + // that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on + // Linux as the actual port will be allocated by the OS. + core.Address address = 2 [(validate.rules).message = {required: true}]; + + // A list of filter chains to consider for this listener. The + // :ref:`FilterChain ` with the most specific + // :ref:`FilterChainMatch ` criteria is used on a + // connection. + // + // Example using SNI for filter chain selection can be found in the + // :ref:`FAQ entry `. + repeated listener.FilterChain filter_chains = 3; + + // If a connection is redirected using *iptables*, the port on which the proxy + // receives it might be different from the original destination address. When this flag is set to + // true, the listener hands off redirected connections to the listener associated with the + // original destination address. If there is no listener associated with the original destination + // address, the connection is handled by the listener that receives it. Defaults to false. + // + // .. attention:: + // + // This field is deprecated. Use :ref:`an original_dst ` + // :ref:`listener filter ` instead. + // + // Note that hand off to another listener is *NOT* performed without this flag. Once + // :ref:`FilterChainMatch ` is implemented this flag + // will be removed, as filter chain matching can be used to select a filter chain based on the + // restored destination address. + google.protobuf.BoolValue use_original_dst = 4 [deprecated = true]; + + // Soft limit on size of the listener’s new connection read and write buffers. + // If unspecified, an implementation defined default is applied (1MiB). + google.protobuf.UInt32Value per_connection_buffer_limit_bytes = 5; + + // Listener metadata. + core.Metadata metadata = 6; + + // [#not-implemented-hide:] + DeprecatedV1 deprecated_v1 = 7; + + // The type of draining to perform at a listener-wide level. + DrainType drain_type = 8; + + // Listener filters have the opportunity to manipulate and augment the connection metadata that + // is used in connection filter chain matching, for example. These filters are run before any in + // :ref:`filter_chains `. Order matters as the + // filters are processed sequentially right after a socket has been accepted by the listener, and + // before a connection is created. + // UDP Listener filters can be specified when the protocol in the listener socket address in + // :ref:`protocol ` is :ref:'UDP + // `. + // UDP listeners currently support a single filter. + repeated listener.ListenerFilter listener_filters = 9; + + // The timeout to wait for all listener filters to complete operation. If the timeout is reached, + // the accepted socket is closed without a connection being created unless + // `continue_on_listener_filters_timeout` is set to true. Specify 0 to disable the + // timeout. If not specified, a default timeout of 15s is used. + google.protobuf.Duration listener_filters_timeout = 15; + + // Whether a connection should be created when listener filters timeout. Default is false. + // + // .. attention:: + // + // Some listener filters, such as :ref:`Proxy Protocol filter + // `, should not be used with this option. It will cause + // unexpected behavior when a connection is created. + bool continue_on_listener_filters_timeout = 17; + + // Whether the listener should be set as a transparent socket. + // When this flag is set to true, connections can be redirected to the listener using an + // *iptables* *TPROXY* target, in which case the original source and destination addresses and + // ports are preserved on accepted connections. This flag should be used in combination with + // :ref:`an original_dst ` :ref:`listener filter + // ` to mark the connections' local addresses as + // "restored." This can be used to hand off each redirected connection to another listener + // associated with the connection's destination address. Direct connections to the socket without + // using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are + // therefore treated as if they were redirected. + // When this flag is set to false, the listener's socket is explicitly reset as non-transparent. + // Setting this flag requires Envoy to run with the *CAP_NET_ADMIN* capability. + // When this flag is not set (default), the socket is not modified, i.e. the transparent option + // is neither set nor reset. + google.protobuf.BoolValue transparent = 10; + + // Whether the listener should set the *IP_FREEBIND* socket option. When this + // flag is set to true, listeners can be bound to an IP address that is not + // configured on the system running Envoy. When this flag is set to false, the + // option *IP_FREEBIND* is disabled on the socket. When this flag is not set + // (default), the socket is not modified, i.e. the option is neither enabled + // nor disabled. + google.protobuf.BoolValue freebind = 11; + + // Additional socket options that may not be present in Envoy source code or + // precompiled binaries. + repeated core.SocketOption socket_options = 13; + + // Whether the listener should accept TCP Fast Open (TFO) connections. + // When this flag is set to a value greater than 0, the option TCP_FASTOPEN is enabled on + // the socket, with a queue length of the specified size + // (see `details in RFC7413 `_). + // When this flag is set to 0, the option TCP_FASTOPEN is disabled on the socket. + // When this flag is not set (default), the socket is not modified, + // i.e. the option is neither enabled nor disabled. + // + // On Linux, the net.ipv4.tcp_fastopen kernel parameter must include flag 0x2 to enable + // TCP_FASTOPEN. + // See `ip-sysctl.txt `_. + // + // On macOS, only values of 0, 1, and unset are valid; other values may result in an error. + // To set the queue length on macOS, set the net.inet.tcp.fastopen_backlog kernel parameter. + google.protobuf.UInt32Value tcp_fast_open_queue_length = 12; + + // Specifies the intended direction of the traffic relative to the local Envoy. + core.TrafficDirection traffic_direction = 16; + + // If the protocol in the listener socket address in :ref:`protocol + // ` is :ref:'UDP + // `, this field specifies the actual udp listener to create, + // i.e. :ref:`udp_listener_name + // ` = "raw_udp_listener" for + // creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". + listener.UdpListenerConfig udp_listener_config = 18; + + // [#not-implemented-hide:] + // Used to represent an API listener, which is used in non-proxy clients. The type of API + // exposed to the non-proxy application depends on the type of API listener. + // When this field is set, no other field except for :ref:`name` + // should be set. + // [#next-major-version: In the v3 API, instead of this messy approach where the socket + // listener fields are directly in the top-level Listener message and the API listener types + // are in the ApiListener message, the socket listener messages should be in their own message, + // and the top-level Listener should essentially be a oneof that selects between the + // socket listener and the various types of API listener. That way, a given Listener message + // can structurally only contain the fields of the relevant type.] + config.listener.v2.ApiListener api_listener = 19; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/listener.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/listener.proto new file mode 100644 index 00000000000..949075840dd --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/listener.proto @@ -0,0 +1,208 @@ +syntax = "proto3"; + +package envoy.api.v2.listener; + +option java_outer_classname = "ListenerProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.listener"; +option csharp_namespace = "Envoy.Api.V2.ListenerNS"; +option ruby_package = "Envoy.Api.V2.ListenerNS"; + +import "envoy/api/v2/auth/cert.proto"; +import "envoy/api/v2/core/address.proto"; +import "envoy/api/v2/core/base.proto"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Listener components] +// Listener :ref:`configuration overview ` + +message Filter { + reserved 3; + + // The name of the filter to instantiate. The name must match a + // :ref:`supported filter `. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Filter specific configuration which depends on the filter being + // instantiated. See the supported filters for further documentation. + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 4; + } +} + +// Specifies the match criteria for selecting a specific filter chain for a +// listener. +// +// In order for a filter chain to be selected, *ALL* of its criteria must be +// fulfilled by the incoming connection, properties of which are set by the +// networking stack and/or listener filters. +// +// The following order applies: +// +// 1. Destination port. +// 2. Destination IP address. +// 3. Server name (e.g. SNI for TLS protocol), +// 4. Transport protocol. +// 5. Application protocols (e.g. ALPN for TLS protocol). +// 6. Source type (e.g. any, local or external network). +// 7. Source IP address. +// 8. Source port. +// +// For criteria that allow ranges or wildcards, the most specific value in any +// of the configured filter chains that matches the incoming connection is going +// to be used (e.g. for SNI ``www.example.com`` the most specific match would be +// ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter +// chain without ``server_names`` requirements). +// +// [#comment: Implemented rules are kept in the preference order, with deprecated fields +// listed at the end, because that's how we want to list them in the docs. +// +// [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] +message FilterChainMatch { + enum ConnectionSourceType { + // Any connection source matches. + ANY = 0; + + // Match a connection originating from the same host. + LOCAL = 1; + + // Match a connection originating from a different host. + EXTERNAL = 2; + } + + reserved 1; + + // Optional destination port to consider when use_original_dst is set on the + // listener in determining a filter chain match. + google.protobuf.UInt32Value destination_port = 8 [(validate.rules).uint32 = {lte: 65535 gte: 1}]; + + // If non-empty, an IP address and prefix length to match addresses when the + // listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + repeated core.CidrRange prefix_ranges = 3; + + // If non-empty, an IP address and suffix length to match addresses when the + // listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + // [#not-implemented-hide:] + string address_suffix = 4; + + // [#not-implemented-hide:] + google.protobuf.UInt32Value suffix_len = 5; + + // Specifies the connection source IP match type. Can be any, local or external network. + ConnectionSourceType source_type = 12 [(validate.rules).enum = {defined_only: true}]; + + // The criteria is satisfied if the source IP address of the downstream + // connection is contained in at least one of the specified subnets. If the + // parameter is not specified or the list is empty, the source IP address is + // ignored. + repeated core.CidrRange source_prefix_ranges = 6; + + // The criteria is satisfied if the source port of the downstream connection + // is contained in at least one of the specified ports. If the parameter is + // not specified, the source port is ignored. + repeated uint32 source_ports = 7 + [(validate.rules).repeated = {items {uint32 {lte: 65535 gte: 1}}}]; + + // If non-empty, a list of server names (e.g. SNI for TLS protocol) to consider when determining + // a filter chain match. Those values will be compared against the server names of a new + // connection, when detected by one of the listener filters. + // + // The server name will be matched against all wildcard domains, i.e. ``www.example.com`` + // will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. + // + // Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. + // + // .. attention:: + // + // See the :ref:`FAQ entry ` on how to configure SNI for more + // information. + repeated string server_names = 11; + + // If non-empty, a transport protocol to consider when determining a filter chain match. + // This value will be compared against the transport protocol of a new connection, when + // it's detected by one of the listener filters. + // + // Suggested values include: + // + // * ``raw_buffer`` - default, used when no transport protocol is detected, + // * ``tls`` - set by :ref:`envoy.listener.tls_inspector ` + // when TLS protocol is detected. + string transport_protocol = 9; + + // If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when + // determining a filter chain match. Those values will be compared against the application + // protocols of a new connection, when detected by one of the listener filters. + // + // Suggested values include: + // + // * ``http/1.1`` - set by :ref:`envoy.listener.tls_inspector + // `, + // * ``h2`` - set by :ref:`envoy.listener.tls_inspector ` + // + // .. attention:: + // + // Currently, only :ref:`TLS Inspector ` provides + // application protocol detection based on the requested + // `ALPN `_ values. + // + // However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, + // and matching on values other than ``h2`` is going to lead to a lot of false negatives, + // unless all connecting clients are known to use ALPN. + repeated string application_protocols = 10; +} + +// A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and +// various other parameters. +message FilterChain { + // The criteria to use when matching a connection to this filter chain. + FilterChainMatch filter_chain_match = 1; + + // The TLS context for this filter chain. + auth.DownstreamTlsContext tls_context = 2; + + // A list of individual network filters that make up the filter chain for + // connections established with the listener. Order matters as the filters are + // processed sequentially as connection events happen. Note: If the filter + // list is empty, the connection will close by default. + repeated Filter filters = 3; + + // Whether the listener should expect a PROXY protocol V1 header on new + // connections. If this option is enabled, the listener will assume that that + // remote address of the connection is the one specified in the header. Some + // load balancers including the AWS ELB support this option. If the option is + // absent or set to false, Envoy will use the physical peer address of the + // connection as the remote address. + google.protobuf.BoolValue use_proxy_proto = 4; + + // [#not-implemented-hide:] filter chain metadata. + core.Metadata metadata = 5; + + // See :ref:`base.TransportSocket` description. + core.TransportSocket transport_socket = 6; + + // [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no + // name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter + // chain is to be dynamically updated or removed via FCDS a unique name must be provided. + string name = 7; +} + +message ListenerFilter { + // The name of the filter to instantiate. The name must match a + // :ref:`supported filter `. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Filter specific configuration which depends on the filter being instantiated. + // See the supported filters for further documentation. + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/udp_listener_config.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/udp_listener_config.proto new file mode 100644 index 00000000000..4b489b99884 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/listener/udp_listener_config.proto @@ -0,0 +1,30 @@ +syntax = "proto3"; + +package envoy.api.v2.listener; + +option java_outer_classname = "UdpListenerConfigProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.listener"; +option csharp_namespace = "Envoy.Api.V2.ListenerNS"; +option ruby_package = "Envoy.Api.V2.ListenerNS"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + +// [#protodoc-title: Udp Listener Config] +// Listener :ref:`configuration overview ` + +message UdpListenerConfig { + // Used to look up UDP listener factory, matches "raw_udp_listener" or + // "quic_listener" to create a specific udp listener. + // If not specified, treat as "raw_udp_listener". + string udp_listener_name = 1; + + // Used to create a specific listener factory. To some factory, e.g. + // "raw_udp_listener", config is not needed. + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/rds.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/rds.proto new file mode 100644 index 00000000000..120c4bd4e32 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/rds.proto @@ -0,0 +1,131 @@ +syntax = "proto3"; + +package envoy.api.v2; + +option java_outer_classname = "RdsProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2"; +option java_generic_services = true; + +import "envoy/api/v2/core/base.proto"; +import "envoy/api/v2/core/config_source.proto"; +import "envoy/api/v2/discovery.proto"; +import "envoy/api/v2/route/route.proto"; + +import "google/api/annotations.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: HTTP route configuration] +// * Routing :ref:`architecture overview ` +// * HTTP :ref:`router filter ` + +// The resource_names field in DiscoveryRequest specifies a route configuration. +// This allows an Envoy configuration with multiple HTTP listeners (and +// associated HTTP connection manager filters) to use different route +// configurations. Each listener will bind its HTTP connection manager filter to +// a route table via this identifier. +service RouteDiscoveryService { + rpc StreamRoutes(stream DiscoveryRequest) returns (stream DiscoveryResponse) { + } + + rpc DeltaRoutes(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) { + } + + rpc FetchRoutes(DiscoveryRequest) returns (DiscoveryResponse) { + option (google.api.http) = { + post: "/v2/discovery:routes" + body: "*" + }; + } +} + +// Virtual Host Discovery Service (VHDS) is used to dynamically update the list of virtual hosts for +// a given RouteConfiguration. If VHDS is configured a virtual host list update will be triggered +// during the processing of an HTTP request if a route for the request cannot be resolved. The +// :ref:`resource_names_subscribe ` +// field contains a list of virtual host names or aliases to track. The contents of an alias would +// be the contents of a *host* or *authority* header used to make an http request. An xDS server +// will match an alias to a virtual host based on the content of :ref:`domains' +// ` field. The *resource_names_unsubscribe* field contains +// a list of virtual host names that have been :ref:`unsubscribed ` +// from the routing table associated with the RouteConfiguration. +service VirtualHostDiscoveryService { + rpc DeltaVirtualHosts(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) { + } +} + +// [#comment:next free field: 10] +message RouteConfiguration { + // The name of the route configuration. For example, it might match + // :ref:`route_config_name + // ` in + // :ref:`envoy_api_msg_config.filter.network.http_connection_manager.v2.Rds`. + string name = 1; + + // An array of virtual hosts that make up the route table. + repeated route.VirtualHost virtual_hosts = 2; + + // An array of virtual hosts will be dynamically loaded via the VHDS API. + // Both *virtual_hosts* and *vhds* fields will be used when present. *virtual_hosts* can be used + // for a base routing table or for infrequently changing virtual hosts. *vhds* is used for + // on-demand discovery of virtual hosts. The contents of these two fields will be merged to + // generate a routing table for a given RouteConfiguration, with *vhds* derived configuration + // taking precedence. + // [#not-implemented-hide:] + Vhds vhds = 9; + + // Optionally specifies a list of HTTP headers that the connection manager + // will consider to be internal only. If they are found on external requests they will be cleaned + // prior to filter invocation. See :ref:`config_http_conn_man_headers_x-envoy-internal` for more + // information. + repeated string internal_only_headers = 3; + + // Specifies a list of HTTP headers that should be added to each response that + // the connection manager encodes. Headers specified at this level are applied + // after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or + // :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + // header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption response_headers_to_add = 4 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each response + // that the connection manager encodes. + repeated string response_headers_to_remove = 5; + + // Specifies a list of HTTP headers that should be added to each request + // routed by the HTTP connection manager. Headers specified at this level are + // applied after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or + // :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + // header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption request_headers_to_add = 6 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each request + // routed by the HTTP connection manager. + repeated string request_headers_to_remove = 8; + + // An optional boolean that specifies whether the clusters that the route + // table refers to will be validated by the cluster manager. If set to true + // and a route refers to a non-existent cluster, the route table will not + // load. If set to false and a route refers to a non-existent cluster, the + // route table will load and the router filter will return a 404 if the route + // is selected at runtime. This setting defaults to true if the route table + // is statically defined via the :ref:`route_config + // ` + // option. This setting default to false if the route table is loaded dynamically via the + // :ref:`rds + // ` + // option. Users may wish to override the default behavior in certain cases (for example when + // using CDS with a static route table). + google.protobuf.BoolValue validate_clusters = 7; +} + +// [#not-implemented-hide:] +message Vhds { + // Configuration source specifier for VHDS. + core.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/route/route.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/route/route.proto new file mode 100644 index 00000000000..c4fe54419b1 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/route/route.proto @@ -0,0 +1,1398 @@ +syntax = "proto3"; + +package envoy.api.v2.route; + +option java_outer_classname = "RouteProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2.route"; + +import "envoy/api/v2/core/base.proto"; +import "envoy/type/matcher/regex.proto"; +import "envoy/type/matcher/string.proto"; +import "envoy/type/percent.proto"; +import "envoy/type/range.proto"; + +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: HTTP route] +// * Routing :ref:`architecture overview ` +// * HTTP :ref:`router filter ` + +// The top level element in the routing configuration is a virtual host. Each virtual host has +// a logical name as well as a set of domains that get routed to it based on the incoming request's +// host header. This allows a single listener to service multiple top level domain path trees. Once +// a virtual host is selected based on the domain, the routes are processed in order to see which +// upstream cluster to route to or whether to perform a redirect. +// [#comment:next free field: 17] +message VirtualHost { + enum TlsRequirementType { + // No TLS requirement for the virtual host. + NONE = 0; + + // External requests must use TLS. If a request is external and it is not + // using TLS, a 301 redirect will be sent telling the client to use HTTPS. + EXTERNAL_ONLY = 1; + + // All requests must use TLS. If a request is not using TLS, a 301 redirect + // will be sent telling the client to use HTTPS. + ALL = 2; + } + + reserved 9; + + // The logical name of the virtual host. This is used when emitting certain + // statistics but is not relevant for routing. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // A list of domains (host/authority header) that will be matched to this + // virtual host. Wildcard hosts are supported in the suffix or prefix form. + // + // Domain search order: + // 1. Exact domain names: ``www.foo.com``. + // 2. Suffix domain wildcards: ``*.foo.com`` or ``*-bar.foo.com``. + // 3. Prefix domain wildcards: ``foo.*`` or ``foo-*``. + // 4. Special wildcard ``*`` matching any domain. + // + // .. note:: + // + // The wildcard will not match the empty string. + // e.g. ``*-bar.foo.com`` will match ``baz-bar.foo.com`` but not ``-bar.foo.com``. + // The longest wildcards match first. + // Only a single virtual host in the entire route configuration can match on ``*``. A domain + // must be unique across all virtual hosts or the config will fail to load. + repeated string domains = 2 [(validate.rules).repeated = {min_items: 1}]; + + // The list of routes that will be matched, in order, for incoming requests. + // The first route that matches will be used. + repeated Route routes = 3; + + // Specifies the type of TLS enforcement the virtual host expects. If this option is not + // specified, there is no TLS requirement for the virtual host. + TlsRequirementType require_tls = 4; + + // A list of virtual clusters defined for this virtual host. Virtual clusters + // are used for additional statistics gathering. + repeated VirtualCluster virtual_clusters = 5; + + // Specifies a set of rate limit configurations that will be applied to the + // virtual host. + repeated RateLimit rate_limits = 6; + + // Specifies a list of HTTP headers that should be added to each request + // handled by this virtual host. Headers specified at this level are applied + // after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the + // enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + // details on header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption request_headers_to_add = 7 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each request + // handled by this virtual host. + repeated string request_headers_to_remove = 13; + + // Specifies a list of HTTP headers that should be added to each response + // handled by this virtual host. Headers specified at this level are applied + // after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the + // enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + // details on header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption response_headers_to_add = 10 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each response + // handled by this virtual host. + repeated string response_headers_to_remove = 11; + + // Indicates that the virtual host has a CORS policy. + CorsPolicy cors = 8; + + // The per_filter_config field can be used to provide virtual host-specific + // configurations for filters. The key should match the filter name, such as + // *envoy.buffer* for the HTTP buffer filter. Use of this field is filter + // specific; see the :ref:`HTTP filter documentation ` + // for if and how it is utilized. + map per_filter_config = 12; + + // The per_filter_config field can be used to provide virtual host-specific + // configurations for filters. The key should match the filter name, such as + // *envoy.buffer* for the HTTP buffer filter. Use of this field is filter + // specific; see the :ref:`HTTP filter documentation ` + // for if and how it is utilized. + map typed_per_filter_config = 15; + + // Decides whether the :ref:`x-envoy-attempt-count + // ` header should be included + // in the upstream request. Setting this option will cause it to override any existing header + // value, so in the case of two Envoys on the request path with this option enabled, the upstream + // will see the attempt count as perceived by the second Envoy. Defaults to false. + // This header is unaffected by the + // :ref:`suppress_envoy_headers + // ` flag. + bool include_request_attempt_count = 14; + + // Indicates the retry policy for all routes in this virtual host. Note that setting a + // route level entry will take precedence over this config and it'll be treated + // independently (e.g.: values are not inherited). + RetryPolicy retry_policy = 16; + + // Indicates the hedge policy for all routes in this virtual host. Note that setting a + // route level entry will take precedence over this config and it'll be treated + // independently (e.g.: values are not inherited). + HedgePolicy hedge_policy = 17; +} + +// A route is both a specification of how to match a request as well as an indication of what to do +// next (e.g., redirect, forward, rewrite, etc.). +// +// .. attention:: +// +// Envoy supports routing on HTTP method via :ref:`header matching +// `. +// [#comment:next free field: 15] +message Route { + reserved 6; + + // Name for the route. + string name = 14; + + // Route matching parameters. + RouteMatch match = 1 [(validate.rules).message = {required: true}]; + + oneof action { + option (validate.required) = true; + + // Route request to some upstream cluster. + RouteAction route = 2; + + // Return a redirect. + RedirectAction redirect = 3; + + // Return an arbitrary HTTP response directly, without proxying. + DirectResponseAction direct_response = 7; + } + + // The Metadata field can be used to provide additional information + // about the route. It can be used for configuration, stats, and logging. + // The metadata should go under the filter namespace that will need it. + // For instance, if the metadata is intended for the Router filter, + // the filter name should be specified as *envoy.router*. + core.Metadata metadata = 4; + + // Decorator for the matched route. + Decorator decorator = 5; + + // The per_filter_config field can be used to provide route-specific + // configurations for filters. The key should match the filter name, such as + // *envoy.buffer* for the HTTP buffer filter. Use of this field is filter + // specific; see the :ref:`HTTP filter documentation ` for + // if and how it is utilized. + map per_filter_config = 8; + + // The per_filter_config field can be used to provide route-specific + // configurations for filters. The key should match the filter name, such as + // *envoy.buffer* for the HTTP buffer filter. Use of this field is filter + // specific; see the :ref:`HTTP filter documentation ` for + // if and how it is utilized. + map typed_per_filter_config = 13; + + // Specifies a set of headers that will be added to requests matching this + // route. Headers specified at this level are applied before headers from the + // enclosing :ref:`envoy_api_msg_route.VirtualHost` and + // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + // header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption request_headers_to_add = 9 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each request + // matching this route. + repeated string request_headers_to_remove = 12; + + // Specifies a set of headers that will be added to responses to requests + // matching this route. Headers specified at this level are applied before + // headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and + // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + // details on header value syntax, see the documentation on + // :ref:`custom request headers `. + repeated core.HeaderValueOption response_headers_to_add = 10 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each response + // to requests matching this route. + repeated string response_headers_to_remove = 11; + + // Presence of the object defines whether the connection manager's tracing configuration + // is overridden by this route specific instance. + Tracing tracing = 15; +} + +// Compared to the :ref:`cluster ` field that specifies a +// single upstream cluster as the target of a request, the :ref:`weighted_clusters +// ` option allows for specification of +// multiple upstream clusters along with weights that indicate the percentage of +// traffic to be forwarded to each cluster. The router selects an upstream cluster based on the +// weights. +// [#comment:next free field: 11] +message WeightedCluster { + message ClusterWeight { + reserved 7; + + // Name of the upstream cluster. The cluster must exist in the + // :ref:`cluster manager configuration `. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // An integer between 0 and :ref:`total_weight + // `. When a request matches the route, + // the choice of an upstream cluster is determined by its weight. The sum of weights across all + // entries in the clusters array must add up to the total_weight, which defaults to 100. + google.protobuf.UInt32Value weight = 2; + + // Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in + // the upstream cluster with metadata matching what is set in this field will be considered for + // load balancing. Note that this will be merged with what's provided in :ref: + // `RouteAction.MetadataMatch `, with values + // here taking precedence. The filter name should be specified as *envoy.lb*. + core.Metadata metadata_match = 3; + + // Specifies a list of headers to be added to requests when this cluster is selected + // through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + // Headers specified at this level are applied before headers from the enclosing + // :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and + // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + // header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption request_headers_to_add = 4 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of HTTP headers that should be removed from each request when + // this cluster is selected through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + repeated string request_headers_to_remove = 9; + + // Specifies a list of headers to be added to responses when this cluster is selected + // through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + // Headers specified at this level are applied before headers from the enclosing + // :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and + // :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + // header value syntax, see the documentation on :ref:`custom request headers + // `. + repeated core.HeaderValueOption response_headers_to_add = 5 + [(validate.rules).repeated = {max_items: 1000}]; + + // Specifies a list of headers to be removed from responses when this cluster is selected + // through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + repeated string response_headers_to_remove = 6; + + // The per_filter_config field can be used to provide weighted cluster-specific + // configurations for filters. The key should match the filter name, such as + // *envoy.buffer* for the HTTP buffer filter. Use of this field is filter + // specific; see the :ref:`HTTP filter documentation ` + // for if and how it is utilized. + map per_filter_config = 8; + + // The per_filter_config field can be used to provide weighted cluster-specific + // configurations for filters. The key should match the filter name, such as + // *envoy.buffer* for the HTTP buffer filter. Use of this field is filter + // specific; see the :ref:`HTTP filter documentation ` + // for if and how it is utilized. + map typed_per_filter_config = 10; + } + + // Specifies one or more upstream clusters associated with the route. + repeated ClusterWeight clusters = 1 [(validate.rules).repeated = {min_items: 1}]; + + // Specifies the total weight across all clusters. The sum of all cluster weights must equal this + // value, which must be greater than 0. Defaults to 100. + google.protobuf.UInt32Value total_weight = 3 [(validate.rules).uint32 = {gte: 1}]; + + // Specifies the runtime key prefix that should be used to construct the + // runtime keys associated with each cluster. When the *runtime_key_prefix* is + // specified, the router will look for weights associated with each upstream + // cluster under the key *runtime_key_prefix* + "." + *cluster[i].name* where + // *cluster[i]* denotes an entry in the clusters array field. If the runtime + // key for the cluster does not exist, the value specified in the + // configuration file will be used as the default weight. See the :ref:`runtime documentation + // ` for how key names map to the underlying implementation. + string runtime_key_prefix = 2; +} + +message RouteMatch { + message GrpcRouteMatchOptions { + } + + reserved 5; + + oneof path_specifier { + option (validate.required) = true; + + // If specified, the route is a prefix rule meaning that the prefix must + // match the beginning of the *:path* header. + string prefix = 1; + + // If specified, the route is an exact path rule meaning that the path must + // exactly match the *:path* header once the query string is removed. + string path = 2; + + // If specified, the route is a regular expression rule meaning that the + // regex must match the *:path* header once the query string is removed. The entire path + // (without the query string) must match the regex. The rule will not match if only a + // subsequence of the *:path* header matches the regex. The regex grammar is defined `here + // `_. + // + // Examples: + // + // * The regex ``/b[io]t`` matches the path */bit* + // * The regex ``/b[io]t`` matches the path */bot* + // * The regex ``/b[io]t`` does not match the path */bite* + // * The regex ``/b[io]t`` does not match the path */bit/bot* + // + // .. attention:: + // This field has been deprecated in favor of `safe_regex` as it is not safe for use with + // untrusted input in all cases. + string regex = 3 [(validate.rules).string = {max_bytes: 1024}, deprecated = true]; + + // If specified, the route is a regular expression rule meaning that the + // regex must match the *:path* header once the query string is removed. The entire path + // (without the query string) must match the regex. The rule will not match if only a + // subsequence of the *:path* header matches the regex. + // + // [#next-major-version: In the v3 API we should redo how path specification works such + // that we utilize StringMatcher, and additionally have consistent options around whether we + // strip query strings, do a case sensitive match, etc. In the interim it will be too disruptive + // to deprecate the existing options. We should even consider whether we want to do away with + // path_specifier entirely and just rely on a set of header matchers which can already match + // on :path, etc. The issue with that is it is unclear how to generically deal with query string + // stripping. This needs more thought.] + type.matcher.RegexMatcher safe_regex = 10 [(validate.rules).message = {required: true}]; + } + + // Indicates that prefix/path matching should be case insensitive. The default + // is true. + google.protobuf.BoolValue case_sensitive = 4; + + // Indicates that the route should additionally match on a runtime key. Every time the route + // is considered for a match, it must also fall under the percentage of matches indicated by + // this field. For some fraction N/D, a random number in the range [0,D) is selected. If the + // number is <= the value of the numerator N, or if the key is not present, the default + // value, the router continues to evaluate the remaining match criteria. A runtime_fraction + // route configuration can be used to roll out route changes in a gradual manner without full + // code/config deploys. Refer to the :ref:`traffic shifting + // ` docs for additional documentation. + // + // .. note:: + // + // Parsing this field is implemented such that the runtime key's data may be represented + // as a FractionalPercent proto represented as JSON/YAML and may also be represented as an + // integer with the assumption that the value is an integral percentage out of 100. For + // instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent + // whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. + core.RuntimeFractionalPercent runtime_fraction = 9; + + // Specifies a set of headers that the route should match on. The router will + // check the request’s headers against all the specified headers in the route + // config. A match will happen if all the headers in the route are present in + // the request with the same values (or based on presence if the value field + // is not in the config). + repeated HeaderMatcher headers = 6; + + // Specifies a set of URL query parameters on which the route should + // match. The router will check the query string from the *path* header + // against all the specified query parameters. If the number of specified + // query parameters is nonzero, they all must match the *path* header's + // query string for a match to occur. + repeated QueryParameterMatcher query_parameters = 7; + + // If specified, only gRPC requests will be matched. The router will check + // that the content-type header has a application/grpc or one of the various + // application/grpc+ values. + GrpcRouteMatchOptions grpc = 8; +} + +// [#comment:next free field: 11] +message CorsPolicy { + // Specifies the origins that will be allowed to do CORS requests. + // + // An origin is allowed if either allow_origin or allow_origin_regex match. + // + // .. attention:: + // This field has been deprecated in favor of `allow_origin_string_match`. + repeated string allow_origin = 1 [deprecated = true]; + + // Specifies regex patterns that match allowed origins. + // + // An origin is allowed if either allow_origin or allow_origin_regex match. + // + // .. attention:: + // This field has been deprecated in favor of `allow_origin_string_match` as it is not safe for + // use with untrusted input in all cases. + repeated string allow_origin_regex = 8 + [(validate.rules).repeated = {items {string {max_bytes: 1024}}}, deprecated = true]; + + // Specifies string patterns that match allowed origins. An origin is allowed if any of the + // string matchers match. + repeated type.matcher.StringMatcher allow_origin_string_match = 11; + + // Specifies the content for the *access-control-allow-methods* header. + string allow_methods = 2; + + // Specifies the content for the *access-control-allow-headers* header. + string allow_headers = 3; + + // Specifies the content for the *access-control-expose-headers* header. + string expose_headers = 4; + + // Specifies the content for the *access-control-max-age* header. + string max_age = 5; + + // Specifies whether the resource allows credentials. + google.protobuf.BoolValue allow_credentials = 6; + + oneof enabled_specifier { + // Specifies if CORS is enabled. Defaults to true. Only effective on route. + // + // .. attention:: + // + // **This field is deprecated**. Set the + // :ref:`filter_enabled` field instead. + google.protobuf.BoolValue enabled = 7 [deprecated = true]; + + // Specifies if CORS is enabled. + // + // More information on how this can be controlled via runtime can be found + // :ref:`here `. + // + // .. note:: + // + // This field defaults to 100/:ref:`HUNDRED + // `. + core.RuntimeFractionalPercent filter_enabled = 9; + } + + // Specifies if CORS policies are evaluated and tracked when filter is off but + // does not enforce any policies. + // + // More information on how this can be controlled via runtime can be found + // :ref:`here `. + // + // .. note:: + // + // This field defaults to 100/:ref:`HUNDRED + // `. + core.RuntimeFractionalPercent shadow_enabled = 10; +} + +// [#comment:next free field: 30] +message RouteAction { + enum ClusterNotFoundResponseCode { + // HTTP status code - 503 Service Unavailable. + SERVICE_UNAVAILABLE = 0; + + // HTTP status code - 404 Not Found. + NOT_FOUND = 1; + } + + // Configures :ref:`internal redirect ` behavior. + enum InternalRedirectAction { + PASS_THROUGH_INTERNAL_REDIRECT = 0; + HANDLE_INTERNAL_REDIRECT = 1; + } + + // The router is capable of shadowing traffic from one cluster to another. The current + // implementation is "fire and forget," meaning Envoy will not wait for the shadow cluster to + // respond before returning the response from the primary cluster. All normal statistics are + // collected for the shadow cluster making this feature useful for testing. + // + // During shadowing, the host/authority header is altered such that *-shadow* is appended. This is + // useful for logging. For example, *cluster1* becomes *cluster1-shadow*. + message RequestMirrorPolicy { + // Specifies the cluster that requests will be mirrored to. The cluster must + // exist in the cluster manager configuration. + string cluster = 1 [(validate.rules).string = {min_bytes: 1}]; + + // If not specified, all requests to the target cluster will be mirrored. If + // specified, Envoy will lookup the runtime key to get the % of requests to + // mirror. Valid values are from 0 to 10000, allowing for increments of + // 0.01% of requests to be mirrored. If the runtime key is specified in the + // configuration but not present in runtime, 0 is the default and thus 0% of + // requests will be mirrored. + // + // .. attention:: + // + // **This field is deprecated**. Set the + // :ref:`runtime_fraction + // ` field instead. + string runtime_key = 2 [deprecated = true]; + + // If both :ref:`runtime_key + // ` and this field are not + // specified, all requests to the target cluster will be mirrored. + // + // If specified, this field takes precedence over the `runtime_key` field and requests must also + // fall under the percentage of matches indicated by this field. + // + // For some fraction N/D, a random number in the range [0,D) is selected. If the + // number is <= the value of the numerator N, or if the key is not present, the default + // value, the request will be mirrored. + // + // .. note:: + // + // Parsing this field is implemented such that the runtime key's data may be represented + // as a :ref:`FractionalPercent ` proto represented + // as JSON/YAML and may also be represented as an integer with the assumption that the value + // is an integral percentage out of 100. For instance, a runtime key lookup returning the + // value "42" would parse as a `FractionalPercent` whose numerator is 42 and denominator is + // HUNDRED. This is behaviour is different to that of the deprecated `runtime_key` field, + // where the implicit denominator is 10000. + core.RuntimeFractionalPercent runtime_fraction = 3; + } + + // Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer + // `. + message HashPolicy { + message Header { + // The name of the request header that will be used to obtain the hash + // key. If the request header is not present, no hash will be produced. + string header_name = 1 [(validate.rules).string = {min_bytes: 1}]; + } + + // Envoy supports two types of cookie affinity: + // + // 1. Passive. Envoy takes a cookie that's present in the cookies header and + // hashes on its value. + // + // 2. Generated. Envoy generates and sets a cookie with an expiration (TTL) + // on the first request from the client in its response to the client, + // based on the endpoint the request gets sent to. The client then + // presents this on the next and all subsequent requests. The hash of + // this is sufficient to ensure these requests get sent to the same + // endpoint. The cookie is generated by hashing the source and + // destination ports and addresses so that multiple independent HTTP2 + // streams on the same connection will independently receive the same + // cookie, even if they arrive at the Envoy simultaneously. + message Cookie { + // The name of the cookie that will be used to obtain the hash key. If the + // cookie is not present and ttl below is not set, no hash will be + // produced. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // If specified, a cookie with the TTL will be generated if the cookie is + // not present. If the TTL is present and zero, the generated cookie will + // be a session cookie. + google.protobuf.Duration ttl = 2; + + // The name of the path for the cookie. If no path is specified here, no path + // will be set for the cookie. + string path = 3; + } + + message ConnectionProperties { + // Hash on source IP address. + bool source_ip = 1; + } + + oneof policy_specifier { + option (validate.required) = true; + + // Header hash policy. + Header header = 1; + + // Cookie hash policy. + Cookie cookie = 2; + + // Connection properties hash policy. + ConnectionProperties connection_properties = 3; + } + + // The flag that shortcircuits the hash computing. This field provides a + // 'fallback' style of configuration: "if a terminal policy doesn't work, + // fallback to rest of the policy list", it saves time when the terminal + // policy works. + // + // If true, and there is already a hash computed, ignore rest of the + // list of hash polices. + // For example, if the following hash methods are configured: + // + // ========= ======== + // specifier terminal + // ========= ======== + // Header A true + // Header B false + // Header C false + // ========= ======== + // + // The generateHash process ends if policy "header A" generates a hash, as + // it's a terminal policy. + bool terminal = 4; + } + + // Allows enabling and disabling upgrades on a per-route basis. + // This overrides any enabled/disabled upgrade filter chain specified in the + // HttpConnectionManager + // :ref:upgrade_configs` + // ` + // but does not affect any custom filter chain specified there. + message UpgradeConfig { + // The case-insensitive name of this upgrade, e.g. "websocket". + // For each upgrade type present in upgrade_configs, requests with + // Upgrade: [upgrade_type] will be proxied upstream. + string upgrade_type = 1; + + // Determines if upgrades are available on this route. Defaults to true. + google.protobuf.BoolValue enabled = 2; + } + + reserved 12, 18, 19, 16, 22, 21; + + oneof cluster_specifier { + option (validate.required) = true; + + // Indicates the upstream cluster to which the request should be routed + // to. + string cluster = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Envoy will determine the cluster to route to by reading the value of the + // HTTP header named by cluster_header from the request headers. If the + // header is not found or the referenced cluster does not exist, Envoy will + // return a 404 response. + // + // .. attention:: + // + // Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 + // *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + string cluster_header = 2 [(validate.rules).string = {min_bytes: 1}]; + + // Multiple upstream clusters can be specified for a given route. The + // request is routed to one of the upstream clusters based on weights + // assigned to each cluster. See + // :ref:`traffic splitting ` + // for additional documentation. + WeightedCluster weighted_clusters = 3; + } + + // The HTTP status code to use when configured cluster is not found. + // The default response code is 503 Service Unavailable. + ClusterNotFoundResponseCode cluster_not_found_response_code = 20 + [(validate.rules).enum = {defined_only: true}]; + + // Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints + // in the upstream cluster with metadata matching what's set in this field will be considered + // for load balancing. If using :ref:`weighted_clusters + // `, metadata will be merged, with values + // provided there taking precedence. The filter name should be specified as *envoy.lb*. + core.Metadata metadata_match = 4; + + // Indicates that during forwarding, the matched prefix (or path) should be + // swapped with this value. This option allows application URLs to be rooted + // at a different path from those exposed at the reverse proxy layer. The router filter will + // place the original path before rewrite into the :ref:`x-envoy-original-path + // ` header. + // + // .. attention:: + // + // Pay careful attention to the use of trailing slashes in the + // :ref:`route's match ` prefix value. + // Stripping a prefix from a path requires multiple Routes to handle all cases. For example, + // rewriting */prefix* to */* and */prefix/etc* to */etc* cannot be done in a single + // :ref:`Route `, as shown by the below config entries: + // + // .. code-block:: yaml + // + // - match: + // prefix: "/prefix/" + // route: + // prefix_rewrite: "/" + // - match: + // prefix: "/prefix" + // route: + // prefix_rewrite: "/" + // + // Having above entries in the config, requests to */prefix* will be stripped to */*, while + // requests to */prefix/etc* will be stripped to */etc*. + string prefix_rewrite = 5; + + oneof host_rewrite_specifier { + // Indicates that during forwarding, the host header will be swapped with + // this value. + string host_rewrite = 6; + + // Indicates that during forwarding, the host header will be swapped with + // the hostname of the upstream host chosen by the cluster manager. This + // option is applicable only when the destination cluster for a route is of + // type *strict_dns* or *logical_dns*. Setting this to true with other cluster + // types has no effect. + google.protobuf.BoolValue auto_host_rewrite = 7; + + // Indicates that during forwarding, the host header will be swapped with the content of given + // downstream or :ref:`custom ` header. + // If header value is empty, host header is left intact. + // + // .. attention:: + // + // Pay attention to the potential security implications of using this option. Provided header + // must come from trusted source. + string auto_host_rewrite_header = 29; + } + + // Specifies the upstream timeout for the route. If not specified, the default is 15s. This + // spans between the point at which the entire downstream request (i.e. end-of-stream) has been + // processed and when the upstream response has been completely processed. A value of 0 will + // disable the route's timeout. + // + // .. note:: + // + // This timeout includes all retries. See also + // :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, + // :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the + // :ref:`retry overview `. + google.protobuf.Duration timeout = 8; + + // Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, + // although the connection manager wide :ref:`stream_idle_timeout + // ` + // will still apply. A value of 0 will completely disable the route's idle timeout, even if a + // connection manager stream idle timeout is configured. + // + // The idle timeout is distinct to :ref:`timeout + // `, which provides an upper bound + // on the upstream response time; :ref:`idle_timeout + // ` instead bounds the amount + // of time the request's stream may be idle. + // + // After header decoding, the idle timeout will apply on downstream and + // upstream request events. Each time an encode/decode event for headers or + // data is processed for the stream, the timer will be reset. If the timeout + // fires, the stream is terminated with a 408 Request Timeout error code if no + // upstream response header has been received, otherwise a stream reset + // occurs. + google.protobuf.Duration idle_timeout = 24; + + // Indicates that the route has a retry policy. Note that if this is set, + // it'll take precedence over the virtual host level retry policy entirely + // (e.g.: policies are not merged, most internal one becomes the enforced policy). + RetryPolicy retry_policy = 9; + + // Indicates that the route has a request mirroring policy. + RequestMirrorPolicy request_mirror_policy = 10; + + // Optionally specifies the :ref:`routing priority `. + // [#comment:TODO(htuch): add (validate.rules).enum.defined_only = true once + // https://github.com/lyft/protoc-gen-validate/issues/42 is resolved.] + core.RoutingPriority priority = 11; + + // Specifies a set of rate limit configurations that could be applied to the + // route. + repeated RateLimit rate_limits = 13; + + // Specifies if the rate limit filter should include the virtual host rate + // limits. By default, if the route configured rate limits, the virtual host + // :ref:`rate_limits ` are not applied to the + // request. + google.protobuf.BoolValue include_vh_rate_limits = 14; + + // Specifies a list of hash policies to use for ring hash load balancing. Each + // hash policy is evaluated individually and the combined result is used to + // route the request. The method of combination is deterministic such that + // identical lists of hash policies will produce the same hash. Since a hash + // policy examines specific parts of a request, it can fail to produce a hash + // (i.e. if the hashed header is not present). If (and only if) all configured + // hash policies fail to generate a hash, no hash will be produced for + // the route. In this case, the behavior is the same as if no hash policies + // were specified (i.e. the ring hash load balancer will choose a random + // backend). If a hash policy has the "terminal" attribute set to true, and + // there is already a hash generated, the hash is returned immediately, + // ignoring the rest of the hash policy list. + repeated HashPolicy hash_policy = 15; + + // Indicates that the route has a CORS policy. + CorsPolicy cors = 17; + + // If present, and the request is a gRPC request, use the + // `grpc-timeout header `_, + // or its default value (infinity) instead of + // :ref:`timeout `, but limit the applied timeout + // to the maximum value specified here. If configured as 0, the maximum allowed timeout for + // gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used + // and gRPC requests time out like any other requests using + // :ref:`timeout ` or its default. + // This can be used to prevent unexpected upstream request timeouts due to potentially long + // time gaps between gRPC request and response in gRPC streaming mode. + google.protobuf.Duration max_grpc_timeout = 23; + + // If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting + // the provided duration from the header. This is useful in allowing Envoy to set its global + // timeout to be less than that of the deadline imposed by the calling client, which makes it more + // likely that Envoy will handle the timeout instead of having the call canceled by the client. + // The offset will only be applied if the provided grpc_timeout is greater than the offset. This + // ensures that the offset will only ever decrease the timeout and never set it to 0 (meaning + // infinity). + google.protobuf.Duration grpc_timeout_offset = 28; + + repeated UpgradeConfig upgrade_configs = 25; + + InternalRedirectAction internal_redirect_action = 26; + + // Indicates that the route has a hedge policy. Note that if this is set, + // it'll take precedence over the virtual host level hedge policy entirely + // (e.g.: policies are not merged, most internal one becomes the enforced policy). + HedgePolicy hedge_policy = 27; +} + +// HTTP retry :ref:`architecture overview `. +// [#comment:next free field: 10] +message RetryPolicy { + message RetryPriority { + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } + } + + message RetryHostPredicate { + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } + } + + message RetryBackOff { + // Specifies the base interval between retries. This parameter is required and must be greater + // than zero. Values less than 1 ms are rounded up to 1 ms. + // See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's + // back-off algorithm. + google.protobuf.Duration base_interval = 1 [(validate.rules).duration = { + required: true + gt {} + }]; + + // Specifies the maximum interval between retries. This parameter is optional, but must be + // greater than or equal to the `base_interval` if set. The default is 10 times the + // `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion + // of Envoy's back-off algorithm. + google.protobuf.Duration max_interval = 2 [(validate.rules).duration = {gt {}}]; + } + + // Specifies the conditions under which retry takes place. These are the same + // conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and + // :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. + string retry_on = 1; + + // Specifies the allowed number of retries. This parameter is optional and + // defaults to 1. These are the same conditions documented for + // :ref:`config_http_filters_router_x-envoy-max-retries`. + google.protobuf.UInt32Value num_retries = 2; + + // Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The + // same conditions documented for + // :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. + // + // .. note:: + // + // If left unspecified, Envoy will use the global + // :ref:`route timeout ` for the request. + // Consequently, when using a :ref:`5xx ` based + // retry policy, a request that times out will not be retried as the total timeout budget + // would have been exhausted. + google.protobuf.Duration per_try_timeout = 3; + + // Specifies an implementation of a RetryPriority which is used to determine the + // distribution of load across priorities used for retries. Refer to + // :ref:`retry plugin configuration ` for more details. + RetryPriority retry_priority = 4; + + // Specifies a collection of RetryHostPredicates that will be consulted when selecting a host + // for retries. If any of the predicates reject the host, host selection will be reattempted. + // Refer to :ref:`retry plugin configuration ` for more + // details. + repeated RetryHostPredicate retry_host_predicate = 5; + + // The maximum number of times host selection will be reattempted before giving up, at which + // point the host that was last selected will be routed to. If unspecified, this will default to + // retrying once. + int64 host_selection_retry_max_attempts = 6; + + // HTTP status codes that should trigger a retry in addition to those specified by retry_on. + repeated uint32 retriable_status_codes = 7; + + // Specifies parameters that control retry back off. This parameter is optional, in which case the + // default base interval is 25 milliseconds or, if set, the current value of the + // `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times + // the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` + // describes Envoy's back-off algorithm. + RetryBackOff retry_back_off = 8; + + // HTTP response headers that trigger a retry if present in the response. A retry will be + // triggered if any of the header matches match the upstream response headers. + // The field is only consulted if 'retriable-headers' retry policy is active. + repeated HeaderMatcher retriable_headers = 9; + + // HTTP headers which must be present in the request for retries to be attempted. + repeated HeaderMatcher retriable_request_headers = 10; +} + +// HTTP request hedging :ref:`architecture overview `. +message HedgePolicy { + // Specifies the number of initial requests that should be sent upstream. + // Must be at least 1. + // Defaults to 1. + // [#not-implemented-hide:] + google.protobuf.UInt32Value initial_requests = 1 [(validate.rules).uint32 = {gte: 1}]; + + // Specifies a probability that an additional upstream request should be sent + // on top of what is specified by initial_requests. + // Defaults to 0. + // [#not-implemented-hide:] + type.FractionalPercent additional_request_chance = 2; + + // Indicates that a hedged request should be sent when the per-try timeout + // is hit. This will only occur if the retry policy also indicates that a + // timed out request should be retried. + // Once a timed out request is retried due to per try timeout, the router + // filter will ensure that it is not retried again even if the returned + // response headers would otherwise be retried according the specified + // :ref:`RetryPolicy `. + // Defaults to false. + bool hedge_on_per_try_timeout = 3; +} + +message RedirectAction { + enum RedirectResponseCode { + // Moved Permanently HTTP Status Code - 301. + MOVED_PERMANENTLY = 0; + + // Found HTTP Status Code - 302. + FOUND = 1; + + // See Other HTTP Status Code - 303. + SEE_OTHER = 2; + + // Temporary Redirect HTTP Status Code - 307. + TEMPORARY_REDIRECT = 3; + + // Permanent Redirect HTTP Status Code - 308. + PERMANENT_REDIRECT = 4; + } + + // When the scheme redirection take place, the following rules apply: + // 1. If the source URI scheme is `http` and the port is explicitly + // set to `:80`, the port will be removed after the redirection + // 2. If the source URI scheme is `https` and the port is explicitly + // set to `:443`, the port will be removed after the redirection + oneof scheme_rewrite_specifier { + // The scheme portion of the URL will be swapped with "https". + bool https_redirect = 4; + + // The scheme portion of the URL will be swapped with this value. + string scheme_redirect = 7; + } + + // The host portion of the URL will be swapped with this value. + string host_redirect = 1; + + // The port value of the URL will be swapped with this value. + uint32 port_redirect = 8; + + oneof path_rewrite_specifier { + // The path portion of the URL will be swapped with this value. + string path_redirect = 2; + + // Indicates that during redirection, the matched prefix (or path) + // should be swapped with this value. This option allows redirect URLs be dynamically created + // based on the request. + // + // .. attention:: + // + // Pay attention to the use of trailing slashes as mentioned in + // :ref:`RouteAction's prefix_rewrite `. + string prefix_rewrite = 5; + } + + // The HTTP status code to use in the redirect response. The default response + // code is MOVED_PERMANENTLY (301). + RedirectResponseCode response_code = 3 [(validate.rules).enum = {defined_only: true}]; + + // Indicates that during redirection, the query portion of the URL will + // be removed. Default value is false. + bool strip_query = 6; +} + +message DirectResponseAction { + // Specifies the HTTP response status to be returned. + uint32 status = 1 [(validate.rules).uint32 = {lt: 600 gte: 100}]; + + // Specifies the content of the response body. If this setting is omitted, + // no body is included in the generated response. + // + // .. note:: + // + // Headers can be specified using *response_headers_to_add* in the enclosing + // :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or + // :ref:`envoy_api_msg_route.VirtualHost`. + core.DataSource body = 2; +} + +message Decorator { + // The operation name associated with the request matched to this route. If tracing is + // enabled, this information will be used as the span name reported for this request. + // + // .. note:: + // + // For ingress (inbound) requests, or egress (outbound) responses, this value may be overridden + // by the :ref:`x-envoy-decorator-operation + // ` header. + string operation = 1 [(validate.rules).string = {min_bytes: 1}]; +} + +message Tracing { + // Target percentage of requests managed by this HTTP connection manager that will be force + // traced if the :ref:`x-client-trace-id ` + // header is set. This field is a direct analog for the runtime variable + // 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + // `. + // Default: 100% + type.FractionalPercent client_sampling = 1; + + // Target percentage of requests managed by this HTTP connection manager that will be randomly + // selected for trace generation, if not requested by the client or not forced. This field is + // a direct analog for the runtime variable 'tracing.random_sampling' in the + // :ref:`HTTP Connection Manager `. + // Default: 100% + type.FractionalPercent random_sampling = 2; + + // Target percentage of requests managed by this HTTP connection manager that will be traced + // after all other sampling checks have been applied (client-directed, force tracing, random + // sampling). This field functions as an upper limit on the total configured sampling rate. For + // instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + // of client requests with the appropriate headers to be force traced. This field is a direct + // analog for the runtime variable 'tracing.global_enabled' in the + // :ref:`HTTP Connection Manager `. + // Default: 100% + type.FractionalPercent overall_sampling = 3; +} + +// A virtual cluster is a way of specifying a regex matching rule against +// certain important endpoints such that statistics are generated explicitly for +// the matched requests. The reason this is useful is that when doing +// prefix/path matching Envoy does not always know what the application +// considers to be an endpoint. Thus, it’s impossible for Envoy to generically +// emit per endpoint statistics. However, often systems have highly critical +// endpoints that they wish to get “perfect” statistics on. Virtual cluster +// statistics are perfect in the sense that they are emitted on the downstream +// side such that they include network level failures. +// +// Documentation for :ref:`virtual cluster statistics `. +// +// .. note:: +// +// Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for +// every application endpoint. This is both not easily maintainable and as well the matching and +// statistics output are not free. +message VirtualCluster { + // Specifies a regex pattern to use for matching requests. The entire path of the request + // must match the regex. The regex grammar used is defined `here + // `_. + // + // Examples: + // + // * The regex ``/rides/\d+`` matches the path */rides/0* + // * The regex ``/rides/\d+`` matches the path */rides/123* + // * The regex ``/rides/\d+`` does not match the path */rides/123/456* + // + // .. attention:: + // This field has been deprecated in favor of `headers` as it is not safe for use with + // untrusted input in all cases. + string pattern = 1 [(validate.rules).string = {max_bytes: 1024}, deprecated = true]; + + // Specifies a list of header matchers to use for matching requests. Each specified header must + // match. The pseudo-headers `:path` and `:method` can be used to match the request path and + // method, respectively. + repeated HeaderMatcher headers = 4; + + // Specifies the name of the virtual cluster. The virtual cluster name as well + // as the virtual host name are used when emitting statistics. The statistics are emitted by the + // router filter and are documented :ref:`here `. + string name = 2 [(validate.rules).string = {min_bytes: 1}]; + + // Optionally specifies the HTTP method to match on. For example GET, PUT, + // etc. + // + // .. attention:: + // This field has been deprecated in favor of `headers`. + core.RequestMethod method = 3 [deprecated = true]; +} + +// Global rate limiting :ref:`architecture overview `. +message RateLimit { + message Action { + // The following descriptor entry is appended to the descriptor: + // + // .. code-block:: cpp + // + // ("source_cluster", "") + // + // is derived from the :option:`--service-cluster` option. + message SourceCluster { + } + + // The following descriptor entry is appended to the descriptor: + // + // .. code-block:: cpp + // + // ("destination_cluster", "") + // + // Once a request matches against a route table rule, a routed cluster is determined by one of + // the following :ref:`route table configuration ` + // settings: + // + // * :ref:`cluster ` indicates the upstream cluster + // to route to. + // * :ref:`weighted_clusters ` + // chooses a cluster randomly from a set of clusters with attributed weight. + // * :ref:`cluster_header ` indicates which + // header in the request contains the target cluster. + message DestinationCluster { + } + + // The following descriptor entry is appended when a header contains a key that matches the + // *header_name*: + // + // .. code-block:: cpp + // + // ("", "") + message RequestHeaders { + // The header name to be queried from the request headers. The header’s + // value is used to populate the value of the descriptor entry for the + // descriptor_key. + string header_name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // The key to use in the descriptor entry. + string descriptor_key = 2 [(validate.rules).string = {min_bytes: 1}]; + } + + // The following descriptor entry is appended to the descriptor and is populated using the + // trusted address from :ref:`x-forwarded-for `: + // + // .. code-block:: cpp + // + // ("remote_address", "") + message RemoteAddress { + } + + // The following descriptor entry is appended to the descriptor: + // + // .. code-block:: cpp + // + // ("generic_key", "") + message GenericKey { + // The value to use in the descriptor entry. + string descriptor_value = 1 [(validate.rules).string = {min_bytes: 1}]; + } + + // The following descriptor entry is appended to the descriptor: + // + // .. code-block:: cpp + // + // ("header_match", "") + message HeaderValueMatch { + // The value to use in the descriptor entry. + string descriptor_value = 1 [(validate.rules).string = {min_bytes: 1}]; + + // If set to true, the action will append a descriptor entry when the + // request matches the headers. If set to false, the action will append a + // descriptor entry when the request does not match the headers. The + // default value is true. + google.protobuf.BoolValue expect_match = 2; + + // Specifies a set of headers that the rate limit action should match + // on. The action will check the request’s headers against all the + // specified headers in the config. A match will happen if all the + // headers in the config are present in the request with the same values + // (or based on presence if the value field is not in the config). + repeated HeaderMatcher headers = 3 [(validate.rules).repeated = {min_items: 1}]; + } + + oneof action_specifier { + option (validate.required) = true; + + // Rate limit on source cluster. + SourceCluster source_cluster = 1; + + // Rate limit on destination cluster. + DestinationCluster destination_cluster = 2; + + // Rate limit on request headers. + RequestHeaders request_headers = 3; + + // Rate limit on remote address. + RemoteAddress remote_address = 4; + + // Rate limit on a generic key. + GenericKey generic_key = 5; + + // Rate limit on the existence of request headers. + HeaderValueMatch header_value_match = 6; + } + } + + // Refers to the stage set in the filter. The rate limit configuration only + // applies to filters with the same stage number. The default stage number is + // 0. + // + // .. note:: + // + // The filter supports a range of 0 - 10 inclusively for stage numbers. + google.protobuf.UInt32Value stage = 1 [(validate.rules).uint32 = {lte: 10}]; + + // The key to be set in runtime to disable this rate limit configuration. + string disable_key = 2; + + // A list of actions that are to be applied for this rate limit configuration. + // Order matters as the actions are processed sequentially and the descriptor + // is composed by appending descriptor entries in that sequence. If an action + // cannot append a descriptor entry, no descriptor is generated for the + // configuration. See :ref:`composing actions + // ` for additional documentation. + repeated Action actions = 3 [(validate.rules).repeated = {min_items: 1}]; +} + +// .. attention:: +// +// Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* +// header. Thus, if attempting to match on *Host*, match on *:authority* instead. +// +// .. attention:: +// +// To route on HTTP method, use the special HTTP/2 *:method* header. This works for both +// HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., +// +// .. code-block:: json +// +// { +// "name": ":method", +// "exact_match": "POST" +// } +// +// .. attention:: +// In the absence of any header match specifier, match will default to :ref:`present_match +// `. i.e, a request that has the :ref:`name +// ` header will match, regardless of the header's +// value. +// +// [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] +message HeaderMatcher { + reserved 2, 3; + + // Specifies the name of the header in the request. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Specifies how the header match will be performed to route the request. + oneof header_match_specifier { + // If specified, header match will be performed based on the value of the header. + string exact_match = 4; + + // If specified, this regex string is a regular expression rule which implies the entire request + // header value must match the regex. The rule will not match if only a subsequence of the + // request header value matches the regex. The regex grammar used in the value field is defined + // `here `_. + // + // Examples: + // + // * The regex ``\d{3}`` matches the value *123* + // * The regex ``\d{3}`` does not match the value *1234* + // * The regex ``\d{3}`` does not match the value *123.456* + // + // .. attention:: + // This field has been deprecated in favor of `safe_regex_match` as it is not safe for use + // with untrusted input in all cases. + string regex_match = 5 [(validate.rules).string = {max_bytes: 1024}, deprecated = true]; + + // If specified, this regex string is a regular expression rule which implies the entire request + // header value must match the regex. The rule will not match if only a subsequence of the + // request header value matches the regex. + type.matcher.RegexMatcher safe_regex_match = 11; + + // If specified, header match will be performed based on range. + // The rule will match if the request header value is within this range. + // The entire request header value must represent an integer in base 10 notation: consisting of + // an optional plus or minus sign followed by a sequence of digits. The rule will not match if + // the header value does not represent an integer. Match will fail for empty values, floating + // point numbers or if only a subsequence of the header value is an integer. + // + // Examples: + // + // * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, + // "-1somestring" + type.Int64Range range_match = 6; + + // If specified, header match will be performed based on whether the header is in the + // request. + bool present_match = 7; + + // If specified, header match will be performed based on the prefix of the header value. + // Note: empty prefix is not allowed, please use present_match instead. + // + // Examples: + // + // * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. + string prefix_match = 9 [(validate.rules).string = {min_bytes: 1}]; + + // If specified, header match will be performed based on the suffix of the header value. + // Note: empty suffix is not allowed, please use present_match instead. + // + // Examples: + // + // * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. + string suffix_match = 10 [(validate.rules).string = {min_bytes: 1}]; + } + + // If specified, the match result will be inverted before checking. Defaults to false. + // + // Examples: + // + // * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. + // * The range [-10,0) will match the value -1, so it will not match when inverted. + bool invert_match = 8; +} + +// Query parameter matching treats the query string of a request's :path header +// as an ampersand-separated list of keys and/or key=value elements. +message QueryParameterMatcher { + // Specifies the name of a key that must be present in the requested + // *path*'s query string. + string name = 1 [(validate.rules).string = {min_bytes: 1 max_bytes: 1024}]; + + // Specifies the value of the key. If the value is absent, a request + // that contains the key in its query string will match, whether the + // key appears with a value (e.g., "?debug=true") or not (e.g., "?debug") + // + // ..attention:: + // This field is deprecated. Use an `exact` match inside the `string_match` field. + string value = 3 [deprecated = true]; + + // Specifies whether the query parameter value is a regular expression. + // Defaults to false. The entire query parameter value (i.e., the part to + // the right of the equals sign in "key=value") must match the regex. + // E.g., the regex ``\d+$`` will match *123* but not *a123* or *123a*. + // + // ..attention:: + // This field is deprecated. Use a `safe_regex` match inside the `string_match` field. + google.protobuf.BoolValue regex = 4 [deprecated = true]; + + oneof query_parameter_match_specifier { + // Specifies whether a query parameter value should match against a string. + type.matcher.StringMatcher string_match = 5 [(validate.rules).message = {required: true}]; + + // Specifies whether a query parameter should be present. + bool present_match = 6; + } +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/config/listener/v2/api_listener.proto b/xds/third_party/envoy/src/main/proto/envoy/config/listener/v2/api_listener.proto new file mode 100644 index 00000000000..0c2253596e4 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/config/listener/v2/api_listener.proto @@ -0,0 +1,24 @@ +syntax = "proto3"; + +package envoy.config.listener.v2; + +option java_outer_classname = "ApiListenerProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.config.listener.v2"; + +import "google/protobuf/any.proto"; + +// [#not-implemented-hide:] +// Describes a type of API listener, which is used in non-proxy clients. The type of API +// exposed to the non-proxy application depends on the type of API listener. +message ApiListener { + // The type in this field determines the type of API listener. At present, the following + // types are supported: + // envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager (HTTP) + // [#next-major-version: In the v3 API, replace this Any field with a oneof containing the + // specific config message for each type of API listener. We could not do this in v2 because + // it would have caused circular dependencies for go protos: lds.proto depends on this file, + // and http_connection_manager.proto depends on rds.proto, which is in the same directory as + // lds.proto, so lds.proto cannot depend on this file.] + google.protobuf.Any api_listener = 1; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/type/matcher/regex.proto b/xds/third_party/envoy/src/main/proto/envoy/type/matcher/regex.proto new file mode 100644 index 00000000000..98819364d9e --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/type/matcher/regex.proto @@ -0,0 +1,37 @@ +syntax = "proto3"; + +package envoy.type.matcher; + +option java_outer_classname = "RegexProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.type.matcher"; + +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: RegexMatcher] + +// A regex matcher designed for safety when used with untrusted input. +message RegexMatcher { + // Google's `RE2 `_ regex engine. The regex string must adhere to + // the documented `syntax `_. The engine is designed + // to complete execution in linear time as well as limit the amount of memory used. + message GoogleRE2 { + // This field controls the RE2 "program size" which is a rough estimate of how complex a + // compiled regex is to evaluate. A regex that has a program size greater than the configured + // value will fail to compile. In this case, the configured max program size can be increased + // or the regex can be simplified. If not specified, the default is 100. + google.protobuf.UInt32Value max_program_size = 1; + } + + oneof engine_type { + option (validate.required) = true; + + // Google's RE2 regex engine. + GoogleRE2 google_re2 = 1 [(validate.rules).message = {required: true}]; + } + + // The regex match string. The string must be supported by the configured engine. + string regex = 2 [(validate.rules).string = {min_bytes: 1}]; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/type/matcher/string.proto b/xds/third_party/envoy/src/main/proto/envoy/type/matcher/string.proto new file mode 100644 index 00000000000..f926af343fd --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/type/matcher/string.proto @@ -0,0 +1,66 @@ +syntax = "proto3"; + +package envoy.type.matcher; + +option java_outer_classname = "StringProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.type.matcher"; + +import "envoy/type/matcher/regex.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: StringMatcher] + +// Specifies the way to match a string. +message StringMatcher { + oneof match_pattern { + option (validate.required) = true; + + // The input string must match exactly the string specified here. + // + // Examples: + // + // * *abc* only matches the value *abc*. + string exact = 1; + + // The input string must have the prefix specified here. + // Note: empty prefix is not allowed, please use regex instead. + // + // Examples: + // + // * *abc* matches the value *abc.xyz* + string prefix = 2 [(validate.rules).string = {min_bytes: 1}]; + + // The input string must have the suffix specified here. + // Note: empty prefix is not allowed, please use regex instead. + // + // Examples: + // + // * *abc* matches the value *xyz.abc* + string suffix = 3 [(validate.rules).string = {min_bytes: 1}]; + + // The input string must match the regular expression specified here. + // The regex grammar is defined `here + // `_. + // + // Examples: + // + // * The regex ``\d{3}`` matches the value *123* + // * The regex ``\d{3}`` does not match the value *1234* + // * The regex ``\d{3}`` does not match the value *123.456* + // + // .. attention:: + // This field has been deprecated in favor of `safe_regex` as it is not safe for use with + // untrusted input in all cases. + string regex = 4 [(validate.rules).string = {max_bytes: 1024}, deprecated = true]; + + // The input string must match the regular expression specified here. + RegexMatcher safe_regex = 5 [(validate.rules).message = {required: true}]; + } +} + +// Specifies a list of ways to match a string. +message ListStringMatcher { + repeated StringMatcher patterns = 1 [(validate.rules).repeated = {min_items: 1}]; +} From c0f91efffb5a8291e7a1fd73a9f6547270b5dc2d Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Fri, 18 Oct 2019 11:00:11 -0700 Subject: [PATCH 108/131] xds: import http_connection_manager proto from envoy repo (#6301) --- .../v2/ScopedRoutesDiscoveryServiceGrpc.java | 459 +++++++++++++ xds/third_party/envoy/import.sh | 3 + .../src/main/proto/envoy/api/v2/srds.proto | 133 ++++ .../filter/accesslog/v2/accesslog.proto | 250 ++++++++ .../v2/http_connection_manager.proto | 604 ++++++++++++++++++ 5 files changed, 1449 insertions(+) create mode 100644 xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java create mode 100644 xds/third_party/envoy/src/main/proto/envoy/api/v2/srds.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/config/filter/accesslog/v2/accesslog.proto create mode 100644 xds/third_party/envoy/src/main/proto/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java new file mode 100644 index 00000000000..c19809f816e --- /dev/null +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java @@ -0,0 +1,459 @@ +package io.envoyproxy.envoy.api.v2; + +import static io.grpc.MethodDescriptor.generateFullMethodName; +import static io.grpc.stub.ClientCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ClientCalls.asyncClientStreamingCall; +import static io.grpc.stub.ClientCalls.asyncServerStreamingCall; +import static io.grpc.stub.ClientCalls.asyncUnaryCall; +import static io.grpc.stub.ClientCalls.blockingServerStreamingCall; +import static io.grpc.stub.ClientCalls.blockingUnaryCall; +import static io.grpc.stub.ClientCalls.futureUnaryCall; +import static io.grpc.stub.ServerCalls.asyncBidiStreamingCall; +import static io.grpc.stub.ServerCalls.asyncClientStreamingCall; +import static io.grpc.stub.ServerCalls.asyncServerStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnaryCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall; +import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; + +/** + *
    + * [#protodoc-title: HTTP scoped routing configuration]
    + * * Routing :ref:`architecture overview <arch_overview_http_routing>`
    + * The Scoped Routes Discovery Service (SRDS) API distributes
    + * :ref:`ScopedRouteConfiguration<envoy_api_msg.ScopedRouteConfiguration>`
    + * resources. Each ScopedRouteConfiguration resource represents a "routing
    + * scope" containing a mapping that allows the HTTP connection manager to
    + * dynamically assign a routing table (specified via a
    + * :ref:`RouteConfiguration<envoy_api_msg_RouteConfiguration>` message) to each
    + * HTTP request.
    + * 
    + */ +@javax.annotation.Generated( + value = "by gRPC proto compiler", + comments = "Source: envoy/api/v2/srds.proto") +public final class ScopedRoutesDiscoveryServiceGrpc { + + private ScopedRoutesDiscoveryServiceGrpc() {} + + public static final String SERVICE_NAME = "envoy.api.v2.ScopedRoutesDiscoveryService"; + + // Static method descriptors that strictly reflect the proto. + private static volatile io.grpc.MethodDescriptor getStreamScopedRoutesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "StreamScopedRoutes", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getStreamScopedRoutesMethod() { + io.grpc.MethodDescriptor getStreamScopedRoutesMethod; + if ((getStreamScopedRoutesMethod = ScopedRoutesDiscoveryServiceGrpc.getStreamScopedRoutesMethod) == null) { + synchronized (ScopedRoutesDiscoveryServiceGrpc.class) { + if ((getStreamScopedRoutesMethod = ScopedRoutesDiscoveryServiceGrpc.getStreamScopedRoutesMethod) == null) { + ScopedRoutesDiscoveryServiceGrpc.getStreamScopedRoutesMethod = getStreamScopedRoutesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "StreamScopedRoutes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ScopedRoutesDiscoveryServiceMethodDescriptorSupplier("StreamScopedRoutes")) + .build(); + } + } + } + return getStreamScopedRoutesMethod; + } + + private static volatile io.grpc.MethodDescriptor getDeltaScopedRoutesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "DeltaScopedRoutes", + requestType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + public static io.grpc.MethodDescriptor getDeltaScopedRoutesMethod() { + io.grpc.MethodDescriptor getDeltaScopedRoutesMethod; + if ((getDeltaScopedRoutesMethod = ScopedRoutesDiscoveryServiceGrpc.getDeltaScopedRoutesMethod) == null) { + synchronized (ScopedRoutesDiscoveryServiceGrpc.class) { + if ((getDeltaScopedRoutesMethod = ScopedRoutesDiscoveryServiceGrpc.getDeltaScopedRoutesMethod) == null) { + ScopedRoutesDiscoveryServiceGrpc.getDeltaScopedRoutesMethod = getDeltaScopedRoutesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "DeltaScopedRoutes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ScopedRoutesDiscoveryServiceMethodDescriptorSupplier("DeltaScopedRoutes")) + .build(); + } + } + } + return getDeltaScopedRoutesMethod; + } + + private static volatile io.grpc.MethodDescriptor getFetchScopedRoutesMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "FetchScopedRoutes", + requestType = io.envoyproxy.envoy.api.v2.DiscoveryRequest.class, + responseType = io.envoyproxy.envoy.api.v2.DiscoveryResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getFetchScopedRoutesMethod() { + io.grpc.MethodDescriptor getFetchScopedRoutesMethod; + if ((getFetchScopedRoutesMethod = ScopedRoutesDiscoveryServiceGrpc.getFetchScopedRoutesMethod) == null) { + synchronized (ScopedRoutesDiscoveryServiceGrpc.class) { + if ((getFetchScopedRoutesMethod = ScopedRoutesDiscoveryServiceGrpc.getFetchScopedRoutesMethod) == null) { + ScopedRoutesDiscoveryServiceGrpc.getFetchScopedRoutesMethod = getFetchScopedRoutesMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "FetchScopedRoutes")) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.envoyproxy.envoy.api.v2.DiscoveryResponse.getDefaultInstance())) + .setSchemaDescriptor(new ScopedRoutesDiscoveryServiceMethodDescriptorSupplier("FetchScopedRoutes")) + .build(); + } + } + } + return getFetchScopedRoutesMethod; + } + + /** + * Creates a new async stub that supports all call types for the service + */ + public static ScopedRoutesDiscoveryServiceStub newStub(io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ScopedRoutesDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ScopedRoutesDiscoveryServiceStub(channel, callOptions); + } + }; + return ScopedRoutesDiscoveryServiceStub.newStub(factory, channel); + } + + /** + * Creates a new blocking-style stub that supports unary and streaming output calls on the service + */ + public static ScopedRoutesDiscoveryServiceBlockingStub newBlockingStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ScopedRoutesDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ScopedRoutesDiscoveryServiceBlockingStub(channel, callOptions); + } + }; + return ScopedRoutesDiscoveryServiceBlockingStub.newStub(factory, channel); + } + + /** + * Creates a new ListenableFuture-style stub that supports unary calls on the service + */ + public static ScopedRoutesDiscoveryServiceFutureStub newFutureStub( + io.grpc.Channel channel) { + io.grpc.stub.AbstractStub.StubFactory factory = + new io.grpc.stub.AbstractStub.StubFactory() { + @java.lang.Override + public ScopedRoutesDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ScopedRoutesDiscoveryServiceFutureStub(channel, callOptions); + } + }; + return ScopedRoutesDiscoveryServiceFutureStub.newStub(factory, channel); + } + + /** + *
    +   * [#protodoc-title: HTTP scoped routing configuration]
    +   * * Routing :ref:`architecture overview <arch_overview_http_routing>`
    +   * The Scoped Routes Discovery Service (SRDS) API distributes
    +   * :ref:`ScopedRouteConfiguration<envoy_api_msg.ScopedRouteConfiguration>`
    +   * resources. Each ScopedRouteConfiguration resource represents a "routing
    +   * scope" containing a mapping that allows the HTTP connection manager to
    +   * dynamically assign a routing table (specified via a
    +   * :ref:`RouteConfiguration<envoy_api_msg_RouteConfiguration>` message) to each
    +   * HTTP request.
    +   * 
    + */ + public static abstract class ScopedRoutesDiscoveryServiceImplBase implements io.grpc.BindableService { + + /** + */ + public io.grpc.stub.StreamObserver streamScopedRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getStreamScopedRoutesMethod(), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaScopedRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncUnimplementedStreamingCall(getDeltaScopedRoutesMethod(), responseObserver); + } + + /** + */ + public void fetchScopedRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getFetchScopedRoutesMethod(), responseObserver); + } + + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { + return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) + .addMethod( + getStreamScopedRoutesMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_STREAM_SCOPED_ROUTES))) + .addMethod( + getDeltaScopedRoutesMethod(), + asyncBidiStreamingCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DeltaDiscoveryRequest, + io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse>( + this, METHODID_DELTA_SCOPED_ROUTES))) + .addMethod( + getFetchScopedRoutesMethod(), + asyncUnaryCall( + new MethodHandlers< + io.envoyproxy.envoy.api.v2.DiscoveryRequest, + io.envoyproxy.envoy.api.v2.DiscoveryResponse>( + this, METHODID_FETCH_SCOPED_ROUTES))) + .build(); + } + } + + /** + *
    +   * [#protodoc-title: HTTP scoped routing configuration]
    +   * * Routing :ref:`architecture overview <arch_overview_http_routing>`
    +   * The Scoped Routes Discovery Service (SRDS) API distributes
    +   * :ref:`ScopedRouteConfiguration<envoy_api_msg.ScopedRouteConfiguration>`
    +   * resources. Each ScopedRouteConfiguration resource represents a "routing
    +   * scope" containing a mapping that allows the HTTP connection manager to
    +   * dynamically assign a routing table (specified via a
    +   * :ref:`RouteConfiguration<envoy_api_msg_RouteConfiguration>` message) to each
    +   * HTTP request.
    +   * 
    + */ + public static final class ScopedRoutesDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { + private ScopedRoutesDiscoveryServiceStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ScopedRoutesDiscoveryServiceStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ScopedRoutesDiscoveryServiceStub(channel, callOptions); + } + + /** + */ + public io.grpc.stub.StreamObserver streamScopedRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getStreamScopedRoutesMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public io.grpc.stub.StreamObserver deltaScopedRoutes( + io.grpc.stub.StreamObserver responseObserver) { + return asyncBidiStreamingCall( + getChannel().newCall(getDeltaScopedRoutesMethod(), getCallOptions()), responseObserver); + } + + /** + */ + public void fetchScopedRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getFetchScopedRoutesMethod(), getCallOptions()), request, responseObserver); + } + } + + /** + *
    +   * [#protodoc-title: HTTP scoped routing configuration]
    +   * * Routing :ref:`architecture overview <arch_overview_http_routing>`
    +   * The Scoped Routes Discovery Service (SRDS) API distributes
    +   * :ref:`ScopedRouteConfiguration<envoy_api_msg.ScopedRouteConfiguration>`
    +   * resources. Each ScopedRouteConfiguration resource represents a "routing
    +   * scope" containing a mapping that allows the HTTP connection manager to
    +   * dynamically assign a routing table (specified via a
    +   * :ref:`RouteConfiguration<envoy_api_msg_RouteConfiguration>` message) to each
    +   * HTTP request.
    +   * 
    + */ + public static final class ScopedRoutesDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { + private ScopedRoutesDiscoveryServiceBlockingStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ScopedRoutesDiscoveryServiceBlockingStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ScopedRoutesDiscoveryServiceBlockingStub(channel, callOptions); + } + + /** + */ + public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchScopedRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return blockingUnaryCall( + getChannel(), getFetchScopedRoutesMethod(), getCallOptions(), request); + } + } + + /** + *
    +   * [#protodoc-title: HTTP scoped routing configuration]
    +   * * Routing :ref:`architecture overview <arch_overview_http_routing>`
    +   * The Scoped Routes Discovery Service (SRDS) API distributes
    +   * :ref:`ScopedRouteConfiguration<envoy_api_msg.ScopedRouteConfiguration>`
    +   * resources. Each ScopedRouteConfiguration resource represents a "routing
    +   * scope" containing a mapping that allows the HTTP connection manager to
    +   * dynamically assign a routing table (specified via a
    +   * :ref:`RouteConfiguration<envoy_api_msg_RouteConfiguration>` message) to each
    +   * HTTP request.
    +   * 
    + */ + public static final class ScopedRoutesDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { + private ScopedRoutesDiscoveryServiceFutureStub( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + super(channel, callOptions); + } + + @java.lang.Override + protected ScopedRoutesDiscoveryServiceFutureStub build( + io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + return new ScopedRoutesDiscoveryServiceFutureStub(channel, callOptions); + } + + /** + */ + public com.google.common.util.concurrent.ListenableFuture fetchScopedRoutes( + io.envoyproxy.envoy.api.v2.DiscoveryRequest request) { + return futureUnaryCall( + getChannel().newCall(getFetchScopedRoutesMethod(), getCallOptions()), request); + } + } + + private static final int METHODID_FETCH_SCOPED_ROUTES = 0; + private static final int METHODID_STREAM_SCOPED_ROUTES = 1; + private static final int METHODID_DELTA_SCOPED_ROUTES = 2; + + private static final class MethodHandlers implements + io.grpc.stub.ServerCalls.UnaryMethod, + io.grpc.stub.ServerCalls.ServerStreamingMethod, + io.grpc.stub.ServerCalls.ClientStreamingMethod, + io.grpc.stub.ServerCalls.BidiStreamingMethod { + private final ScopedRoutesDiscoveryServiceImplBase serviceImpl; + private final int methodId; + + MethodHandlers(ScopedRoutesDiscoveryServiceImplBase serviceImpl, int methodId) { + this.serviceImpl = serviceImpl; + this.methodId = methodId; + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public void invoke(Req request, io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_FETCH_SCOPED_ROUTES: + serviceImpl.fetchScopedRoutes((io.envoyproxy.envoy.api.v2.DiscoveryRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + default: + throw new AssertionError(); + } + } + + @java.lang.Override + @java.lang.SuppressWarnings("unchecked") + public io.grpc.stub.StreamObserver invoke( + io.grpc.stub.StreamObserver responseObserver) { + switch (methodId) { + case METHODID_STREAM_SCOPED_ROUTES: + return (io.grpc.stub.StreamObserver) serviceImpl.streamScopedRoutes( + (io.grpc.stub.StreamObserver) responseObserver); + case METHODID_DELTA_SCOPED_ROUTES: + return (io.grpc.stub.StreamObserver) serviceImpl.deltaScopedRoutes( + (io.grpc.stub.StreamObserver) responseObserver); + default: + throw new AssertionError(); + } + } + } + + private static abstract class ScopedRoutesDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoFileDescriptorSupplier, io.grpc.protobuf.ProtoServiceDescriptorSupplier { + ScopedRoutesDiscoveryServiceBaseDescriptorSupplier() {} + + @java.lang.Override + public com.google.protobuf.Descriptors.FileDescriptor getFileDescriptor() { + return io.envoyproxy.envoy.api.v2.SrdsProto.getDescriptor(); + } + + @java.lang.Override + public com.google.protobuf.Descriptors.ServiceDescriptor getServiceDescriptor() { + return getFileDescriptor().findServiceByName("ScopedRoutesDiscoveryService"); + } + } + + private static final class ScopedRoutesDiscoveryServiceFileDescriptorSupplier + extends ScopedRoutesDiscoveryServiceBaseDescriptorSupplier { + ScopedRoutesDiscoveryServiceFileDescriptorSupplier() {} + } + + private static final class ScopedRoutesDiscoveryServiceMethodDescriptorSupplier + extends ScopedRoutesDiscoveryServiceBaseDescriptorSupplier + implements io.grpc.protobuf.ProtoMethodDescriptorSupplier { + private final String methodName; + + ScopedRoutesDiscoveryServiceMethodDescriptorSupplier(String methodName) { + this.methodName = methodName; + } + + @java.lang.Override + public com.google.protobuf.Descriptors.MethodDescriptor getMethodDescriptor() { + return getServiceDescriptor().findMethodByName(methodName); + } + } + + private static volatile io.grpc.ServiceDescriptor serviceDescriptor; + + public static io.grpc.ServiceDescriptor getServiceDescriptor() { + io.grpc.ServiceDescriptor result = serviceDescriptor; + if (result == null) { + synchronized (ScopedRoutesDiscoveryServiceGrpc.class) { + result = serviceDescriptor; + if (result == null) { + serviceDescriptor = result = io.grpc.ServiceDescriptor.newBuilder(SERVICE_NAME) + .setSchemaDescriptor(new ScopedRoutesDiscoveryServiceFileDescriptorSupplier()) + .addMethod(getStreamScopedRoutesMethod()) + .addMethod(getDeltaScopedRoutesMethod()) + .addMethod(getFetchScopedRoutesMethod()) + .build(); + } + } + } + return result; + } +} diff --git a/xds/third_party/envoy/import.sh b/xds/third_party/envoy/import.sh index dab909c62fe..3088c312719 100755 --- a/xds/third_party/envoy/import.sh +++ b/xds/third_party/envoy/import.sh @@ -45,6 +45,9 @@ envoy/api/v2/listener/listener.proto envoy/api/v2/listener/udp_listener_config.proto envoy/api/v2/rds.proto envoy/api/v2/route/route.proto +envoy/api/v2/srds.proto +envoy/config/filter/accesslog/v2/accesslog.proto +envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto envoy/config/listener/v2/api_listener.proto envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto diff --git a/xds/third_party/envoy/src/main/proto/envoy/api/v2/srds.proto b/xds/third_party/envoy/src/main/proto/envoy/api/v2/srds.proto new file mode 100644 index 00000000000..224ae070774 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/api/v2/srds.proto @@ -0,0 +1,133 @@ +syntax = "proto3"; + +package envoy.api.v2; + +option java_outer_classname = "SrdsProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.api.v2"; +option java_generic_services = true; + +import "envoy/api/v2/discovery.proto"; + +import "google/api/annotations.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: HTTP scoped routing configuration] +// * Routing :ref:`architecture overview ` +// +// The Scoped Routes Discovery Service (SRDS) API distributes +// :ref:`ScopedRouteConfiguration` +// resources. Each ScopedRouteConfiguration resource represents a "routing +// scope" containing a mapping that allows the HTTP connection manager to +// dynamically assign a routing table (specified via a +// :ref:`RouteConfiguration` message) to each +// HTTP request. +service ScopedRoutesDiscoveryService { + rpc StreamScopedRoutes(stream DiscoveryRequest) returns (stream DiscoveryResponse) { + } + + rpc DeltaScopedRoutes(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) { + } + + rpc FetchScopedRoutes(DiscoveryRequest) returns (DiscoveryResponse) { + option (google.api.http) = { + post: "/v2/discovery:scoped-routes" + body: "*" + }; + } +} + +// Specifies a routing scope, which associates a +// :ref:`Key` to a +// :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). +// +// The HTTP connection manager builds up a table consisting of these Key to +// RouteConfiguration mappings, and looks up the RouteConfiguration to use per +// request according to the algorithm specified in the +// :ref:`scope_key_builder` +// assigned to the HttpConnectionManager. +// +// For example, with the following configurations (in YAML): +// +// HttpConnectionManager config: +// +// .. code:: +// +// ... +// scoped_routes: +// name: foo-scoped-routes +// scope_key_builder: +// fragments: +// - header_value_extractor: +// name: X-Route-Selector +// element_separator: , +// element: +// separator: = +// key: vip +// +// ScopedRouteConfiguration resources (specified statically via +// :ref:`scoped_route_configurations_list` +// or obtained dynamically via SRDS): +// +// .. code:: +// +// (1) +// name: route-scope1 +// route_configuration_name: route-config1 +// key: +// fragments: +// - string_key: 172.10.10.20 +// +// (2) +// name: route-scope2 +// route_configuration_name: route-config2 +// key: +// fragments: +// - string_key: 172.20.20.30 +// +// A request from a client such as: +// +// .. code:: +// +// GET / HTTP/1.1 +// Host: foo.com +// X-Route-Selector: vip=172.10.10.20 +// +// would result in the routing table defined by the `route-config1` +// RouteConfiguration being assigned to the HTTP request/stream. +// +// [#comment:next free field: 4] +message ScopedRouteConfiguration { + // Specifies a key which is matched against the output of the + // :ref:`scope_key_builder` + // specified in the HttpConnectionManager. The matching is done per HTTP + // request and is dependent on the order of the fragments contained in the + // Key. + message Key { + message Fragment { + oneof type { + option (validate.required) = true; + + // A string to match against. + string string_key = 1; + } + } + + // The ordered set of fragments to match against. The order must match the + // fragments in the corresponding + // :ref:`scope_key_builder`. + repeated Fragment fragments = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + // The name assigned to the routing scope. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an + // RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + // with this scope. + string route_configuration_name = 2 [(validate.rules).string = {min_bytes: 1}]; + + // The key to match against. + Key key = 3 [(validate.rules).message = {required: true}]; +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/config/filter/accesslog/v2/accesslog.proto b/xds/third_party/envoy/src/main/proto/envoy/config/filter/accesslog/v2/accesslog.proto new file mode 100644 index 00000000000..8810e050e95 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/config/filter/accesslog/v2/accesslog.proto @@ -0,0 +1,250 @@ +syntax = "proto3"; + +package envoy.config.filter.accesslog.v2; + +option java_outer_classname = "AccesslogProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.config.filter.accesslog.v2"; + +import "envoy/api/v2/core/base.proto"; +import "envoy/api/v2/route/route.proto"; +import "envoy/type/percent.proto"; + +import "google/protobuf/any.proto"; +import "google/protobuf/struct.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: Common access log types] + +message AccessLog { + // The name of the access log implementation to instantiate. The name must + // match a statically registered access log. Current built-in loggers include: + // + // #. "envoy.file_access_log" + // #. "envoy.http_grpc_access_log" + // #. "envoy.tcp_grpc_access_log" + string name = 1; + + // Filter which is used to determine if the access log needs to be written. + AccessLogFilter filter = 2; + + // Custom configuration that depends on the access log being instantiated. Built-in + // configurations include: + // + // #. "envoy.file_access_log": :ref:`FileAccessLog + // ` + // #. "envoy.http_grpc_access_log": :ref:`HttpGrpcAccessLogConfig + // ` + // #. "envoy.tcp_grpc_access_log": :ref:`TcpGrpcAccessLogConfig + // ` + oneof config_type { + google.protobuf.Struct config = 3; + + google.protobuf.Any typed_config = 4; + } +} + +message AccessLogFilter { + oneof filter_specifier { + option (validate.required) = true; + + // Status code filter. + StatusCodeFilter status_code_filter = 1; + + // Duration filter. + DurationFilter duration_filter = 2; + + // Not health check filter. + NotHealthCheckFilter not_health_check_filter = 3; + + // Traceable filter. + TraceableFilter traceable_filter = 4; + + // Runtime filter. + RuntimeFilter runtime_filter = 5; + + // And filter. + AndFilter and_filter = 6; + + // Or filter. + OrFilter or_filter = 7; + + // Header filter. + HeaderFilter header_filter = 8; + + // Response flag filter. + ResponseFlagFilter response_flag_filter = 9; + + // gRPC status filter. + GrpcStatusFilter grpc_status_filter = 10; + + // Extension filter. + ExtensionFilter extension_filter = 11; + } +} + +// Filter on an integer comparison. +message ComparisonFilter { + enum Op { + // = + EQ = 0; + + // >= + GE = 1; + + // <= + LE = 2; + } + + // Comparison operator. + Op op = 1 [(validate.rules).enum = {defined_only: true}]; + + // Value to compare against. + api.v2.core.RuntimeUInt32 value = 2; +} + +// Filters on HTTP response/status code. +message StatusCodeFilter { + // Comparison. + ComparisonFilter comparison = 1 [(validate.rules).message = {required: true}]; +} + +// Filters on total request duration in milliseconds. +message DurationFilter { + // Comparison. + ComparisonFilter comparison = 1 [(validate.rules).message = {required: true}]; +} + +// Filters for requests that are not health check requests. A health check +// request is marked by the health check filter. +message NotHealthCheckFilter { +} + +// Filters for requests that are traceable. See the tracing overview for more +// information on how a request becomes traceable. +message TraceableFilter { +} + +// Filters for random sampling of requests. +message RuntimeFilter { + // Runtime key to get an optional overridden numerator for use in the *percent_sampled* field. + // If found in runtime, this value will replace the default numerator. + string runtime_key = 1 [(validate.rules).string = {min_bytes: 1}]; + + // The default sampling percentage. If not specified, defaults to 0% with denominator of 100. + type.FractionalPercent percent_sampled = 2; + + // By default, sampling pivots on the header + // :ref:`x-request-id` being present. If + // :ref:`x-request-id` is present, the filter will + // consistently sample across multiple hosts based on the runtime key value and the value + // extracted from :ref:`x-request-id`. If it is + // missing, or *use_independent_randomness* is set to true, the filter will randomly sample based + // on the runtime key value alone. *use_independent_randomness* can be used for logging kill + // switches within complex nested :ref:`AndFilter + // ` and :ref:`OrFilter + // ` blocks that are easier to reason about + // from a probability perspective (i.e., setting to true will cause the filter to behave like + // an independent random variable when composed within logical operator filters). + bool use_independent_randomness = 3; +} + +// Performs a logical “and” operation on the result of each filter in filters. +// Filters are evaluated sequentially and if one of them returns false, the +// filter returns false immediately. +message AndFilter { + repeated AccessLogFilter filters = 1 [(validate.rules).repeated = {min_items: 2}]; +} + +// Performs a logical “or” operation on the result of each individual filter. +// Filters are evaluated sequentially and if one of them returns true, the +// filter returns true immediately. +message OrFilter { + repeated AccessLogFilter filters = 2 [(validate.rules).repeated = {min_items: 2}]; +} + +// Filters requests based on the presence or value of a request header. +message HeaderFilter { + // Only requests with a header which matches the specified HeaderMatcher will pass the filter + // check. + api.v2.route.HeaderMatcher header = 1 [(validate.rules).message = {required: true}]; +} + +// Filters requests that received responses with an Envoy response flag set. +// A list of the response flags can be found +// in the access log formatter :ref:`documentation`. +message ResponseFlagFilter { + // Only responses with the any of the flags listed in this field will be logged. + // This field is optional. If it is not specified, then any response flag will pass + // the filter check. + repeated string flags = 1 [(validate.rules).repeated = { + items { + string { + in: "LH" + in: "UH" + in: "UT" + in: "LR" + in: "UR" + in: "UF" + in: "UC" + in: "UO" + in: "NR" + in: "DI" + in: "FI" + in: "RL" + in: "UAEX" + in: "RLSE" + in: "DC" + in: "URX" + in: "SI" + in: "IH" + } + } + }]; +} + +// Filters gRPC requests based on their response status. If a gRPC status is not provided, the +// filter will infer the status from the HTTP status code. +message GrpcStatusFilter { + enum Status { + OK = 0; + CANCELED = 1; + UNKNOWN = 2; + INVALID_ARGUMENT = 3; + DEADLINE_EXCEEDED = 4; + NOT_FOUND = 5; + ALREADY_EXISTS = 6; + PERMISSION_DENIED = 7; + RESOURCE_EXHAUSTED = 8; + FAILED_PRECONDITION = 9; + ABORTED = 10; + OUT_OF_RANGE = 11; + UNIMPLEMENTED = 12; + INTERNAL = 13; + UNAVAILABLE = 14; + DATA_LOSS = 15; + UNAUTHENTICATED = 16; + } + + // Logs only responses that have any one of the gRPC statuses in this field. + repeated Status statuses = 1 [(validate.rules).repeated = {items {enum {defined_only: true}}}]; + + // If included and set to true, the filter will instead block all responses with a gRPC status or + // inferred gRPC status enumerated in statuses, and allow all other responses. + bool exclude = 2; +} + +// Extension filter is statically registered at runtime. +message ExtensionFilter { + // The name of the filter implementation to instantiate. The name must + // match a statically registered filter. + string name = 1; + + // Custom configuration that depends on the filter being instantiated. + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 3; + } +} diff --git a/xds/third_party/envoy/src/main/proto/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto b/xds/third_party/envoy/src/main/proto/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto new file mode 100644 index 00000000000..efdfb4be939 --- /dev/null +++ b/xds/third_party/envoy/src/main/proto/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto @@ -0,0 +1,604 @@ +syntax = "proto3"; + +package envoy.config.filter.network.http_connection_manager.v2; + +option java_outer_classname = "HttpConnectionManagerProto"; +option java_multiple_files = true; +option java_package = "io.envoyproxy.envoy.config.filter.network.http_connection_manager.v2"; + +import "envoy/api/v2/core/config_source.proto"; +import "envoy/api/v2/core/protocol.proto"; +import "envoy/api/v2/rds.proto"; +import "envoy/api/v2/srds.proto"; +import "envoy/config/filter/accesslog/v2/accesslog.proto"; +import "envoy/type/percent.proto"; + +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/struct.proto"; +import "google/protobuf/wrappers.proto"; + +import "validate/validate.proto"; + +// [#protodoc-title: HTTP connection manager] +// HTTP connection manager :ref:`configuration overview `. + +// [#comment:next free field: 35] +message HttpConnectionManager { + enum CodecType { + // For every new connection, the connection manager will determine which + // codec to use. This mode supports both ALPN for TLS listeners as well as + // protocol inference for plaintext listeners. If ALPN data is available, it + // is preferred, otherwise protocol inference is used. In almost all cases, + // this is the right option to choose for this setting. + AUTO = 0; + + // The connection manager will assume that the client is speaking HTTP/1.1. + HTTP1 = 1; + + // The connection manager will assume that the client is speaking HTTP/2 + // (Envoy does not require HTTP/2 to take place over TLS or to use ALPN. + // Prior knowledge is allowed). + HTTP2 = 2; + } + + enum ServerHeaderTransformation { + // Overwrite any Server header with the contents of server_name. + OVERWRITE = 0; + + // If no Server header is present, append Server server_name + // If a Server header is present, pass it through. + APPEND_IF_ABSENT = 1; + + // Pass through the value of the server header, and do not append a header + // if none is present. + PASS_THROUGH = 2; + } + + // How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + // header. + enum ForwardClientCertDetails { + // Do not send the XFCC header to the next hop. This is the default value. + SANITIZE = 0; + + // When the client connection is mTLS (Mutual TLS), forward the XFCC header + // in the request. + FORWARD_ONLY = 1; + + // When the client connection is mTLS, append the client certificate + // information to the request’s XFCC header and forward it. + APPEND_FORWARD = 2; + + // When the client connection is mTLS, reset the XFCC header with the client + // certificate information and send it to the next hop. + SANITIZE_SET = 3; + + // Always forward the XFCC header in the request, regardless of whether the + // client connection is mTLS. + ALWAYS_FORWARD_ONLY = 4; + } + + message Tracing { + enum OperationName { + // The HTTP listener is used for ingress/incoming requests. + INGRESS = 0; + + // The HTTP listener is used for egress/outgoing requests. + EGRESS = 1; + } + + // The span name will be derived from this field. If + // :ref:`traffic_direction ` is + // specified on the parent listener, then it is used instead of this field. + // + // .. attention:: + // This field has been deprecated in favor of `traffic_direction`. + OperationName operation_name = 1 + [(validate.rules).enum = {defined_only: true}, deprecated = true]; + + // A list of header names used to create tags for the active span. The header name is used to + // populate the tag name, and the header value is used to populate the tag value. The tag is + // created if the specified header name is present in the request's headers. + repeated string request_headers_for_tags = 2; + + // Target percentage of requests managed by this HTTP connection manager that will be force + // traced if the :ref:`x-client-trace-id ` + // header is set. This field is a direct analog for the runtime variable + // 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + // `. + // Default: 100% + type.Percent client_sampling = 3; + + // Target percentage of requests managed by this HTTP connection manager that will be randomly + // selected for trace generation, if not requested by the client or not forced. This field is + // a direct analog for the runtime variable 'tracing.random_sampling' in the + // :ref:`HTTP Connection Manager `. + // Default: 100% + type.Percent random_sampling = 4; + + // Target percentage of requests managed by this HTTP connection manager that will be traced + // after all other sampling checks have been applied (client-directed, force tracing, random + // sampling). This field functions as an upper limit on the total configured sampling rate. For + // instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + // of client requests with the appropriate headers to be force traced. This field is a direct + // analog for the runtime variable 'tracing.global_enabled' in the + // :ref:`HTTP Connection Manager `. + // Default: 100% + type.Percent overall_sampling = 5; + + // Whether to annotate spans with additional data. If true, spans will include logs for stream + // events. + bool verbose = 6; + + // Maximum length of the request path to extract and include in the HttpUrl tag. Used to + // truncate lengthy request paths to meet the needs of a tracing backend. + // Default: 256 + google.protobuf.UInt32Value max_path_tag_length = 7; + } + + message InternalAddressConfig { + // Whether unix socket addresses should be considered internal. + bool unix_sockets = 1; + } + + // [#comment:next free field: 7] + message SetCurrentClientCertDetails { + reserved 2; + + // Whether to forward the subject of the client cert. Defaults to false. + google.protobuf.BoolValue subject = 1; + + // Whether to forward the entire client cert in URL encoded PEM format. This will appear in the + // XFCC header comma separated from other values with the value Cert="PEM". + // Defaults to false. + bool cert = 3; + + // Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM + // format. This will appear in the XFCC header comma separated from other values with the value + // Chain="PEM". + // Defaults to false. + bool chain = 6; + + // Whether to forward the DNS type Subject Alternative Names of the client cert. + // Defaults to false. + bool dns = 4; + + // Whether to forward the URI type Subject Alternative Name of the client cert. Defaults to + // false. + bool uri = 5; + } + + // The configuration for HTTP upgrades. + // For each upgrade type desired, an UpgradeConfig must be added. + // + // .. warning:: + // + // The current implementation of upgrade headers does not handle + // multi-valued upgrade headers. Support for multi-valued headers may be + // added in the future if needed. + // + // .. warning:: + // The current implementation of upgrade headers does not work with HTTP/2 + // upstreams. + message UpgradeConfig { + // The case-insensitive name of this upgrade, e.g. "websocket". + // For each upgrade type present in upgrade_configs, requests with + // Upgrade: [upgrade_type] + // will be proxied upstream. + string upgrade_type = 1; + + // If present, this represents the filter chain which will be created for + // this type of upgrade. If no filters are present, the filter chain for + // HTTP connections will be used for this upgrade type. + repeated HttpFilter filters = 2; + + // Determines if upgrades are enabled or disabled by default. Defaults to true. + // This can be overridden on a per-route basis with :ref:`cluster + // ` as documented in the + // :ref:`upgrade documentation `. + google.protobuf.BoolValue enabled = 3; + } + + reserved 27; + + // Supplies the type of codec that the connection manager should use. + CodecType codec_type = 1 [(validate.rules).enum = {defined_only: true}]; + + // The human readable prefix to use when emitting statistics for the + // connection manager. See the :ref:`statistics documentation ` for + // more information. + string stat_prefix = 2 [(validate.rules).string = {min_bytes: 1}]; + + oneof route_specifier { + option (validate.required) = true; + + // The connection manager’s route table will be dynamically loaded via the RDS API. + Rds rds = 3; + + // The route table for the connection manager is static and is specified in this property. + api.v2.RouteConfiguration route_config = 4; + + // A route table will be dynamically assigned to each request based on request attributes + // (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are + // specified in this message. + ScopedRoutes scoped_routes = 31; + } + + // A list of individual HTTP filters that make up the filter chain for + // requests made to the connection manager. Order matters as the filters are + // processed sequentially as request events happen. + repeated HttpFilter http_filters = 5; + + // Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` + // and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked + // documentation for more information. Defaults to false. + google.protobuf.BoolValue add_user_agent = 6; + + // Presence of the object defines whether the connection manager + // emits :ref:`tracing ` data to the :ref:`configured tracing provider + // `. + Tracing tracing = 7; + + // Additional HTTP/1 settings that are passed to the HTTP/1 codec. + api.v2.core.Http1ProtocolOptions http_protocol_options = 8; + + // Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. + api.v2.core.Http2ProtocolOptions http2_protocol_options = 9; + + // An optional override that the connection manager will write to the server + // header in responses. If not set, the default is *envoy*. + string server_name = 10; + + // Defines the action to be applied to the Server header on the response path. + // By default, Envoy will overwrite the header with the value specified in + // server_name. + ServerHeaderTransformation server_header_transformation = 34 + [(validate.rules).enum = {defined_only: true}]; + + // The maximum request headers size for incoming connections. + // If unconfigured, the default max request headers allowed is 60 KiB. + // Requests that exceed this limit will receive a 431 response. + // The max configurable limit is 96 KiB, based on current implementation + // constraints. + google.protobuf.UInt32Value max_request_headers_kb = 29 + [(validate.rules).uint32 = {lte: 96 gt: 0}]; + + // The idle timeout for connections managed by the connection manager. The + // idle timeout is defined as the period in which there are no active + // requests. If not set, there is no idle timeout. When the idle timeout is + // reached the connection will be closed. If the connection is an HTTP/2 + // connection a drain sequence will occur prior to closing the connection. See + // :ref:`drain_timeout + // `. + google.protobuf.Duration idle_timeout = 11; + + // The stream idle timeout for connections managed by the connection manager. + // If not specified, this defaults to 5 minutes. The default value was selected + // so as not to interfere with any smaller configured timeouts that may have + // existed in configurations prior to the introduction of this feature, while + // introducing robustness to TCP connections that terminate without a FIN. + // + // This idle timeout applies to new streams and is overridable by the + // :ref:`route-level idle_timeout + // `. Even on a stream in + // which the override applies, prior to receipt of the initial request + // headers, the :ref:`stream_idle_timeout + // ` + // applies. Each time an encode/decode event for headers or data is processed + // for the stream, the timer will be reset. If the timeout fires, the stream + // is terminated with a 408 Request Timeout error code if no upstream response + // header has been received, otherwise a stream reset occurs. + // + // Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due + // to the granularity of events presented to the connection manager. For example, while receiving + // very large request headers, it may be the case that there is traffic regularly arriving on the + // wire while the connection manage is only able to observe the end-of-headers event, hence the + // stream may still idle timeout. + // + // A value of 0 will completely disable the connection manager stream idle + // timeout, although per-route idle timeout overrides will continue to apply. + google.protobuf.Duration stream_idle_timeout = 24; + + // A timeout for idle requests managed by the connection manager. + // The timer is activated when the request is initiated, and is disarmed when the last byte of the + // request is sent upstream (i.e. all decoding filters have processed the request), OR when the + // response is initiated. If not specified or set to 0, this timeout is disabled. + google.protobuf.Duration request_timeout = 28; + + // The time that Envoy will wait between sending an HTTP/2 “shutdown + // notification” (GOAWAY frame with max stream ID) and a final GOAWAY frame. + // This is used so that Envoy provides a grace period for new streams that + // race with the final GOAWAY frame. During this grace period, Envoy will + // continue to accept new streams. After the grace period, a final GOAWAY + // frame is sent and Envoy will start refusing new streams. Draining occurs + // both when a connection hits the idle timeout or during general server + // draining. The default grace period is 5000 milliseconds (5 seconds) if this + // option is not specified. + google.protobuf.Duration drain_timeout = 12; + + // The delayed close timeout is for downstream connections managed by the HTTP connection manager. + // It is defined as a grace period after connection close processing has been locally initiated + // during which Envoy will wait for the peer to close (i.e., a TCP FIN/RST is received by Envoy + // from the downstream connection) prior to Envoy closing the socket associated with that + // connection. + // NOTE: This timeout is enforced even when the socket associated with the downstream connection + // is pending a flush of the write buffer. However, any progress made writing data to the socket + // will restart the timer associated with this timeout. This means that the total grace period for + // a socket in this state will be + // +. + // + // Delaying Envoy's connection close and giving the peer the opportunity to initiate the close + // sequence mitigates a race condition that exists when downstream clients do not drain/process + // data in a connection's receive buffer after a remote close has been detected via a socket + // write(). This race leads to such clients failing to process the response code sent by Envoy, + // which could result in erroneous downstream processing. + // + // If the timeout triggers, Envoy will close the connection's socket. + // + // The default timeout is 1000 ms if this option is not specified. + // + // .. NOTE:: + // To be useful in avoiding the race condition described above, this timeout must be set + // to *at least* +<100ms to account for + // a reasonsable "worst" case processing time for a full iteration of Envoy's event loop>. + // + // .. WARNING:: + // A value of 0 will completely disable delayed close processing. When disabled, the downstream + // connection's socket will be closed immediately after the write flush is completed or will + // never close if the write flush does not complete. + google.protobuf.Duration delayed_close_timeout = 26; + + // Configuration for :ref:`HTTP access logs ` + // emitted by the connection manager. + repeated accesslog.v2.AccessLog access_log = 13; + + // If set to true, the connection manager will use the real remote address + // of the client connection when determining internal versus external origin and manipulating + // various headers. If set to false or absent, the connection manager will use the + // :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. See the documentation for + // :ref:`config_http_conn_man_headers_x-forwarded-for`, + // :ref:`config_http_conn_man_headers_x-envoy-internal`, and + // :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. + google.protobuf.BoolValue use_remote_address = 14; + + // The number of additional ingress proxy hops from the right side of the + // :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header to trust when + // determining the origin client's IP address. The default is zero if this option + // is not specified. See the documentation for + // :ref:`config_http_conn_man_headers_x-forwarded-for` for more information. + uint32 xff_num_trusted_hops = 19; + + // Configures what network addresses are considered internal for stats and header sanitation + // purposes. If unspecified, only RFC1918 IP addresses will be considered internal. + // See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more + // information about internal/external addresses. + InternalAddressConfig internal_address_config = 25; + + // If set, Envoy will not append the remote address to the + // :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in + // conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager + // has mutated the request headers. While :ref:`use_remote_address + // ` + // will also suppress XFF addition, it has consequences for logging and other + // Envoy uses of the remote address, so *skip_xff_append* should be used + // when only an elision of XFF addition is intended. + bool skip_xff_append = 21; + + // Via header value to append to request and response headers. If this is + // empty, no via header will be appended. + string via = 22; + + // Whether the connection manager will generate the :ref:`x-request-id + // ` header if it does not exist. This defaults to + // true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature + // is not desired it can be disabled. + google.protobuf.BoolValue generate_request_id = 15; + + // Whether the connection manager will keep the :ref:`x-request-id + // ` header if passed for a request that is edge + // (Edge request is the request from external clients to front Envoy) and not reset it, which + // is the current Envoy behaviour. This defaults to false. + bool preserve_external_request_id = 32; + + // How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + // header. + ForwardClientCertDetails forward_client_cert_details = 16 + [(validate.rules).enum = {defined_only: true}]; + + // This field is valid only when :ref:`forward_client_cert_details + // ` + // is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in + // the client certificate to be forwarded. Note that in the + // :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and + // *By* is always set when the client certificate presents the URI type Subject Alternative Name + // value. + SetCurrentClientCertDetails set_current_client_cert_details = 17; + + // If proxy_100_continue is true, Envoy will proxy incoming "Expect: + // 100-continue" headers upstream, and forward "100 Continue" responses + // downstream. If this is false or not set, Envoy will instead strip the + // "Expect: 100-continue" header, and send a "100 Continue" response itself. + bool proxy_100_continue = 18; + + // If + // :ref:`use_remote_address + // ` + // is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is + // an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. + // This is useful for testing compatibility of upstream services that parse the header value. For + // example, 50.0.0.1 is represented as ::FFFF:50.0.0.1. See `IPv4-Mapped IPv6 Addresses + // `_ for details. This will also affect the + // :ref:`config_http_conn_man_headers_x-envoy-external-address` header. See + // :ref:`http_connection_manager.represent_ipv4_remote_address_as_ipv4_mapped_ipv6 + // ` for runtime + // control. + // [#not-implemented-hide:] + bool represent_ipv4_remote_address_as_ipv4_mapped_ipv6 = 20; + + repeated UpgradeConfig upgrade_configs = 23; + + // Should paths be normalized according to RFC 3986 before any processing of + // requests by HTTP filters or routing? This affects the upstream *:path* header + // as well. For paths that fail this check, Envoy will respond with 400 to + // paths that are malformed. This defaults to false currently but will default + // true in the future. When not specified, this value may be overridden by the + // runtime variable + // :ref:`http_connection_manager.normalize_path`. + // See `Normalization and Comparison ` + // for details of normalization. + // Note that Envoy does not perform + // `case normalization ` + google.protobuf.BoolValue normalize_path = 30; + + // Determines if adjacent slashes in the path are merged into one before any processing of + // requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without + // setting this option, incoming requests with path `//dir///file` will not match against route + // with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of + // `HTTP spec ` and is provided for convenience. + bool merge_slashes = 33; +} + +message Rds { + // Configuration source specifier for RDS. + api.v2.core.ConfigSource config_source = 1 [(validate.rules).message = {required: true}]; + + // The name of the route configuration. This name will be passed to the RDS + // API. This allows an Envoy configuration with multiple HTTP listeners (and + // associated HTTP connection manager filters) to use different route + // configurations. + string route_config_name = 2 [(validate.rules).string = {min_bytes: 1}]; +} + +// This message is used to work around the limitations with 'oneof' and repeated fields. +message ScopedRouteConfigurationsList { + repeated api.v2.ScopedRouteConfiguration scoped_route_configurations = 1 + [(validate.rules).repeated = {min_items: 1}]; +} + +message ScopedRoutes { + // Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These + // keys are matched against a set of :ref:`Key` + // objects assembled from :ref:`ScopedRouteConfiguration` + // messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via + // :ref:`scoped_route_configurations_list`. + // + // Upon receiving a request's headers, the Router will build a key using the algorithm specified + // by this message. This key will be used to look up the routing table (i.e., the + // :ref:`RouteConfiguration`) to use for the request. + message ScopeKeyBuilder { + // Specifies the mechanism for constructing key fragments which are composed into scope keys. + message FragmentBuilder { + // Specifies how the value of a header should be extracted. + // The following example maps the structure of a header to the fields in this message. + // + // .. code:: + // + // <0> <1> <-- index + // X-Header: a=b;c=d + // | || | + // | || \----> + // | || + // | |\----> + // | | + // | \----> + // | + // \----> + // + // Each 'a=b' key-value pair constitutes an 'element' of the header field. + message HeaderValueExtractor { + // Specifies a header field's key value pair to match on. + message KvElement { + // The separator between key and value (e.g., '=' separates 'k=v;...'). + // If an element is an empty string, the element is ignored. + // If an element contains no separator, the whole element is parsed as key and the + // fragment value is an empty string. + // If there are multiple values for a matched key, the first value is returned. + string separator = 1 [(validate.rules).string = {min_bytes: 1}]; + + // The key to match on. + string key = 2 [(validate.rules).string = {min_bytes: 1}]; + } + + // The name of the header field to extract the value from. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // The element separator (e.g., ';' separates 'a;b;c;d'). + // Default: empty string. This causes the entirety of the header field to be extracted. + // If this field is set to an empty string and 'index' is used in the oneof below, 'index' + // must be set to 0. + string element_separator = 2; + + oneof extract_type { + // Specifies the zero based index of the element to extract. + // Note Envoy concatenates multiple values of the same header key into a comma separated + // string, the splitting always happens after the concatenation. + uint32 index = 3; + + // Specifies the key value pair to extract the value from. + KvElement element = 4; + } + } + + oneof type { + option (validate.required) = true; + + // Specifies how a header field's value should be extracted. + HeaderValueExtractor header_value_extractor = 1; + } + } + + // The final scope key consists of the ordered union of these fragments. + repeated FragmentBuilder fragments = 1 [(validate.rules).repeated = {min_items: 1}]; + } + + // The name assigned to the scoped routing configuration. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // The algorithm to use for constructing a scope key for each request. + ScopeKeyBuilder scope_key_builder = 2 [(validate.rules).message = {required: true}]; + + // Configuration source specifier for RDS. + // This config source is used to subscribe to RouteConfiguration resources specified in + // ScopedRouteConfiguration messages. + api.v2.core.ConfigSource rds_config_source = 3 [(validate.rules).message = {required: true}]; + + oneof config_specifier { + option (validate.required) = true; + + // The set of routing scopes corresponding to the HCM. A scope is assigned to a request by + // matching a key constructed from the request's attributes according to the algorithm specified + // by the + // :ref:`ScopeKeyBuilder` + // in this message. + ScopedRouteConfigurationsList scoped_route_configurations_list = 4; + + // The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS + // API. A scope is assigned to a request by matching a key constructed from the request's + // attributes according to the algorithm specified by the + // :ref:`ScopeKeyBuilder` + // in this message. + ScopedRds scoped_rds = 5; + } +} + +message ScopedRds { + // Configuration source specifier for scoped RDS. + api.v2.core.ConfigSource scoped_rds_config_source = 1 + [(validate.rules).message = {required: true}]; +} + +message HttpFilter { + reserved 3; + + // The name of the filter to instantiate. The name must match a + // :ref:`supported filter `. + string name = 1 [(validate.rules).string = {min_bytes: 1}]; + + // Filter specific configuration which depends on the filter being instantiated. See the supported + // filters for further documentation. + oneof config_type { + google.protobuf.Struct config = 2; + + google.protobuf.Any typed_config = 4; + } +} From eef47b26b83d5eaba92f506f280ec49100d791c2 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Fri, 18 Oct 2019 13:00:47 -0700 Subject: [PATCH 109/131] core,grpclb: DnsNameResolver will use srv record by default if grpclb (#6298) --- .../io/grpc/NameResolverRegistryTest.java | 8 ++- .../internal/BaseDnsNameResolverProvider.java | 70 +++++++++++++++++++ .../io/grpc/internal/DnsNameResolver.java | 16 +++-- .../internal/DnsNameResolverProvider.java | 42 ++--------- .../internal/DnsNameResolverProviderTest.java | 10 +++ .../io/grpc/internal/DnsNameResolverTest.java | 3 +- .../SecretGrpclbNameResolverProvider.java | 61 ++++++++++++++++ .../services/io.grpc.NameResolverProvider | 1 + .../SecretGrpclbNameResolverProviderTest.java | 50 +++++++++++++ 9 files changed, 216 insertions(+), 45 deletions(-) create mode 100644 core/src/main/java/io/grpc/internal/BaseDnsNameResolverProvider.java create mode 100644 grpclb/src/main/java/io/grpc/grpclb/SecretGrpclbNameResolverProvider.java create mode 100644 grpclb/src/main/resources/META-INF/services/io.grpc.NameResolverProvider create mode 100644 grpclb/src/test/java/io/grpc/grpclb/SecretGrpclbNameResolverProviderTest.java diff --git a/api/src/test/java/io/grpc/NameResolverRegistryTest.java b/api/src/test/java/io/grpc/NameResolverRegistryTest.java index 1870f312868..abbe10af2ac 100644 --- a/api/src/test/java/io/grpc/NameResolverRegistryTest.java +++ b/api/src/test/java/io/grpc/NameResolverRegistryTest.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import io.grpc.NameResolver.ServiceConfigParser; +import io.grpc.internal.BaseDnsNameResolverProvider; import io.grpc.internal.DnsNameResolverProvider; import java.lang.Thread.UncaughtExceptionHandler; import java.net.URI; @@ -152,8 +153,11 @@ public void newNameResolver_noProvider() { @Test public void baseProviders() { List providers = NameResolverRegistry.getDefaultRegistry().providers(); - assertThat(providers).hasSize(1); - assertThat(providers.get(0)).isInstanceOf(DnsNameResolverProvider.class); + assertThat(providers).hasSize(2); + // 2 name resolvers from grpclb and core + for (NameResolverProvider provider : providers) { + assertThat(provider).isInstanceOf(BaseDnsNameResolverProvider.class); + } assertThat(NameResolverRegistry.getDefaultRegistry().asFactory().getDefaultScheme()) .isEqualTo("dns"); } diff --git a/core/src/main/java/io/grpc/internal/BaseDnsNameResolverProvider.java b/core/src/main/java/io/grpc/internal/BaseDnsNameResolverProvider.java new file mode 100644 index 00000000000..b623ced6b78 --- /dev/null +++ b/core/src/main/java/io/grpc/internal/BaseDnsNameResolverProvider.java @@ -0,0 +1,70 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.internal; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.base.Stopwatch; +import io.grpc.InternalServiceProviders; +import io.grpc.NameResolver; +import io.grpc.NameResolverProvider; +import java.net.URI; + +/** + * Base provider of name resolvers for name agnostic consumption. + */ +public abstract class BaseDnsNameResolverProvider extends NameResolverProvider { + + private static final String SCHEME = "dns"; + + @VisibleForTesting + public static final String ENABLE_GRPCLB_PROPERTY_NAME = + "io.grpc.internal.DnsNameResolverProvider.enable_grpclb"; + + /** Returns boolean value of system property {@link #ENABLE_GRPCLB_PROPERTY_NAME}. */ + protected abstract boolean isSrvEnabled(); + + @Override + public DnsNameResolver newNameResolver(URI targetUri, NameResolver.Args args) { + if (SCHEME.equals(targetUri.getScheme())) { + String targetPath = Preconditions.checkNotNull(targetUri.getPath(), "targetPath"); + Preconditions.checkArgument(targetPath.startsWith("/"), + "the path component (%s) of the target (%s) must start with '/'", targetPath, targetUri); + String name = targetPath.substring(1); + return new DnsNameResolver( + targetUri.getAuthority(), + name, + args, + GrpcUtil.SHARED_CHANNEL_EXECUTOR, + Stopwatch.createUnstarted(), + InternalServiceProviders.isAndroid(getClass().getClassLoader()), + isSrvEnabled()); + } else { + return null; + } + } + + @Override + public String getDefaultScheme() { + return SCHEME; + } + + @Override + protected boolean isAvailable() { + return true; + } +} diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolver.java b/core/src/main/java/io/grpc/internal/DnsNameResolver.java index 8e07dbdb8ec..b85dd79ccb9 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolver.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolver.java @@ -92,8 +92,6 @@ final class DnsNameResolver extends NameResolver { System.getProperty("io.grpc.internal.DnsNameResolverProvider.enable_jndi", "true"); private static final String JNDI_LOCALHOST_PROPERTY = System.getProperty("io.grpc.internal.DnsNameResolverProvider.enable_jndi_localhost", "false"); - private static final String JNDI_SRV_PROPERTY = - System.getProperty("io.grpc.internal.DnsNameResolverProvider.enable_grpclb", "false"); private static final String JNDI_TXT_PROPERTY = System.getProperty("io.grpc.internal.DnsNameResolverProvider.enable_service_config", "false"); @@ -117,8 +115,6 @@ final class DnsNameResolver extends NameResolver { @VisibleForTesting static boolean enableJndiLocalhost = Boolean.parseBoolean(JNDI_LOCALHOST_PROPERTY); @VisibleForTesting - static boolean enableSrv = Boolean.parseBoolean(JNDI_SRV_PROPERTY); - @VisibleForTesting static boolean enableTxt = Boolean.parseBoolean(JNDI_TXT_PROPERTY); private static final ResourceResolverFactory resourceResolverFactory = @@ -152,6 +148,7 @@ final class DnsNameResolver extends NameResolver { /** True if using an executor resource that should be released after use. */ private final boolean usingExecutorResource; + private final boolean enableSrv; private boolean resolving; @@ -159,8 +156,14 @@ final class DnsNameResolver extends NameResolver { // from any thread. private NameResolver.Listener2 listener; - DnsNameResolver(@Nullable String nsAuthority, String name, Args args, - Resource executorResource, Stopwatch stopwatch, boolean isAndroid) { + DnsNameResolver( + @Nullable String nsAuthority, + String name, + Args args, + Resource executorResource, + Stopwatch stopwatch, + boolean isAndroid, + boolean enableSrv) { Preconditions.checkNotNull(args, "args"); // TODO: if a DNS server is provided as nsAuthority, use it. // https://www.captechconsulting.com/blogs/accessing-the-dusty-corners-of-dns-with-java @@ -184,6 +187,7 @@ final class DnsNameResolver extends NameResolver { Preconditions.checkNotNull(args.getSynchronizationContext(), "syncContext"); this.executor = args.getBlockingExecutor(); this.usingExecutorResource = executor == null; + this.enableSrv = enableSrv; } @Override diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolverProvider.java b/core/src/main/java/io/grpc/internal/DnsNameResolverProvider.java index 67e60351631..06ff1c85953 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolverProvider.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolverProvider.java @@ -16,13 +16,6 @@ package io.grpc.internal; -import com.google.common.base.Preconditions; -import com.google.common.base.Stopwatch; -import io.grpc.InternalServiceProviders; -import io.grpc.NameResolver; -import io.grpc.NameResolverProvider; -import java.net.URI; - /** * A provider for {@link DnsNameResolver}. * @@ -38,41 +31,18 @@ *
  1. {@code "dns:///foo.googleapis.com"} (without port)
  2. * */ -public final class DnsNameResolverProvider extends NameResolverProvider { - - private static final String SCHEME = "dns"; +public final class DnsNameResolverProvider extends BaseDnsNameResolverProvider { - @Override - public DnsNameResolver newNameResolver(URI targetUri, NameResolver.Args args) { - if (SCHEME.equals(targetUri.getScheme())) { - String targetPath = Preconditions.checkNotNull(targetUri.getPath(), "targetPath"); - Preconditions.checkArgument(targetPath.startsWith("/"), - "the path component (%s) of the target (%s) must start with '/'", targetPath, targetUri); - String name = targetPath.substring(1); - return new DnsNameResolver( - targetUri.getAuthority(), - name, - args, - GrpcUtil.SHARED_CHANNEL_EXECUTOR, - Stopwatch.createUnstarted(), - InternalServiceProviders.isAndroid(getClass().getClassLoader())); - } else { - return null; - } - } - - @Override - public String getDefaultScheme() { - return SCHEME; - } + private static final boolean SRV_ENABLED = + Boolean.parseBoolean(System.getProperty(ENABLE_GRPCLB_PROPERTY_NAME, "false")); @Override - protected boolean isAvailable() { - return true; + protected boolean isSrvEnabled() { + return SRV_ENABLED; } @Override - protected int priority() { + public int priority() { return 5; } } diff --git a/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java b/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java index 9dc402a93d6..3f5df9bdbbb 100644 --- a/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java +++ b/core/src/test/java/io/grpc/internal/DnsNameResolverProviderTest.java @@ -16,9 +16,12 @@ package io.grpc.internal; +import static com.google.common.truth.Truth.assertThat; +import static io.grpc.internal.BaseDnsNameResolverProvider.ENABLE_GRPCLB_PROPERTY_NAME; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.mock; import io.grpc.NameResolver; @@ -60,4 +63,11 @@ public void newNameResolver() { assertNull( provider.newNameResolver(URI.create("notdns:///localhost:443"), args)); } + + @Test + public void isSrvEnabled_falseByDefault() { + assumeTrue(System.getProperty(ENABLE_GRPCLB_PROPERTY_NAME) == null); + + assertThat(provider.isSrvEnabled()).isFalse(); + } } diff --git a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java index 7214db6edac..6baa87ad0ad 100644 --- a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java +++ b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java @@ -182,7 +182,8 @@ private DnsNameResolver newResolver( private DnsNameResolver newResolver( String name, Stopwatch stopwatch, boolean isAndroid, NameResolver.Args args) { DnsNameResolver dnsResolver = - new DnsNameResolver(null, name, args, fakeExecutorResource, stopwatch, isAndroid); + new DnsNameResolver( + null, name, args, fakeExecutorResource, stopwatch, isAndroid, /* enableSrv= */ false); // By default, using the mocked ResourceResolver to avoid I/O dnsResolver.setResourceResolver(new JndiResourceResolver(recordFetcher)); return dnsResolver; diff --git a/grpclb/src/main/java/io/grpc/grpclb/SecretGrpclbNameResolverProvider.java b/grpclb/src/main/java/io/grpc/grpclb/SecretGrpclbNameResolverProvider.java new file mode 100644 index 00000000000..1856c78c14e --- /dev/null +++ b/grpclb/src/main/java/io/grpc/grpclb/SecretGrpclbNameResolverProvider.java @@ -0,0 +1,61 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.grpclb; + +import io.grpc.internal.BaseDnsNameResolverProvider; + +/** + * A provider for {@code io.grpc.internal.DnsNameResolver} for gRPC lb. + * + *

    It resolves a target URI whose scheme is {@code "dns"}. The (optional) authority of the target + * URI is reserved for the address of alternative DNS server (not implemented yet). The path of the + * target URI, excluding the leading slash {@code '/'}, is treated as the host name and the optional + * port to be resolved by DNS. Example target URIs: + * + *

      + *
    • {@code "dns:///foo.googleapis.com:8080"} (using default DNS)
    • + *
    • {@code "dns://8.8.8.8/foo.googleapis.com:8080"} (using alternative DNS (not implemented + * yet))
    • + *
    • {@code "dns:///foo.googleapis.com"} (without port)
    • + *
    + * + *

    Note: the main difference between {@code io.grpc.DnsNameResolver} is service record is enabled + * by default. + */ +// Make it package-private so that it cannot be directly referenced by users. Java service loader +// requires the provider to be public, but we can hide it under a package-private class. +final class SecretGrpclbNameResolverProvider { + + private SecretGrpclbNameResolverProvider() {} + + public static final class Provider extends BaseDnsNameResolverProvider { + + private static final boolean SRV_ENABLED = + Boolean.parseBoolean(System.getProperty(ENABLE_GRPCLB_PROPERTY_NAME, "true")); + + @Override + protected boolean isSrvEnabled() { + return SRV_ENABLED; + } + + @Override + public int priority() { + // Must be higher than DnsNameResolverProvider#priority. + return 6; + } + } +} diff --git a/grpclb/src/main/resources/META-INF/services/io.grpc.NameResolverProvider b/grpclb/src/main/resources/META-INF/services/io.grpc.NameResolverProvider new file mode 100644 index 00000000000..bf02b5e8470 --- /dev/null +++ b/grpclb/src/main/resources/META-INF/services/io.grpc.NameResolverProvider @@ -0,0 +1 @@ +io.grpc.grpclb.SecretGrpclbNameResolverProvider$Provider diff --git a/grpclb/src/test/java/io/grpc/grpclb/SecretGrpclbNameResolverProviderTest.java b/grpclb/src/test/java/io/grpc/grpclb/SecretGrpclbNameResolverProviderTest.java new file mode 100644 index 00000000000..e5d4b3501f2 --- /dev/null +++ b/grpclb/src/test/java/io/grpc/grpclb/SecretGrpclbNameResolverProviderTest.java @@ -0,0 +1,50 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.grpclb; + +import static com.google.common.truth.Truth.assertThat; +import static io.grpc.internal.BaseDnsNameResolverProvider.ENABLE_GRPCLB_PROPERTY_NAME; +import static org.junit.Assume.assumeTrue; + +import io.grpc.internal.DnsNameResolverProvider; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class SecretGrpclbNameResolverProviderTest { + + @Test + public void priority_shouldBeHigherThanDefaultDnsNameResolver() { + DnsNameResolverProvider defaultDnsNameResolver = new DnsNameResolverProvider(); + SecretGrpclbNameResolverProvider.Provider grpclbDnsNameResolver = + new SecretGrpclbNameResolverProvider.Provider(); + + assertThat(defaultDnsNameResolver.priority()) + .isLessThan(grpclbDnsNameResolver.priority()); + } + + @Test + public void isSrvEnabled_trueByDefault() { + assumeTrue(System.getProperty(ENABLE_GRPCLB_PROPERTY_NAME) == null); + + SecretGrpclbNameResolverProvider.Provider grpclbDnsNameResolver = + new SecretGrpclbNameResolverProvider.Provider(); + + assertThat(grpclbDnsNameResolver.isSrvEnabled()).isTrue(); + } +} \ No newline at end of file From 9dce8797421a72b4f460b63fd6f1119548424b41 Mon Sep 17 00:00:00 2001 From: Chengyuan Zhang Date: Fri, 18 Oct 2019 13:33:56 -0700 Subject: [PATCH 110/131] xds: add fields for EDS server and LRS server in XdsConfig (#6287) --- .../io/grpc/internal/ServiceConfigUtil.java | 20 +++++++ .../grpc/internal/ServiceConfigUtilTest.java | 54 +++++++++++++++++++ .../io/grpc/xds/XdsLoadBalancerProvider.java | 32 +++++++++-- .../grpc/xds/XdsLoadBalancerProviderTest.java | 8 ++- 4 files changed, 108 insertions(+), 6 deletions(-) diff --git a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java index 0f4318a9aab..71e43b00866 100644 --- a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java +++ b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java @@ -48,9 +48,12 @@ public final class ServiceConfigUtil { private static final String SERVICE_CONFIG_METHOD_CONFIG_KEY = "methodConfig"; private static final String SERVICE_CONFIG_LOAD_BALANCING_POLICY_KEY = "loadBalancingPolicy"; private static final String SERVICE_CONFIG_LOAD_BALANCING_CONFIG_KEY = "loadBalancingConfig"; + // TODO(chengyuanzhang): delete this key after shifting to use bootstrap. private static final String XDS_CONFIG_BALANCER_NAME_KEY = "balancerName"; private static final String XDS_CONFIG_CHILD_POLICY_KEY = "childPolicy"; private static final String XDS_CONFIG_FALLBACK_POLICY_KEY = "fallbackPolicy"; + private static final String XDS_CONFIG_EDS_SERVICE_NAME = "edsServiceName"; + private static final String XDS_CONFIG_LRS_SERVER_NAME = "lrsLoadReportingServerName"; private static final String SERVICE_CONFIG_STICKINESS_METADATA_KEY = "stickinessMetadataKey"; private static final String METHOD_CONFIG_NAME_KEY = "name"; private static final String METHOD_CONFIG_TIMEOUT_KEY = "timeout"; @@ -423,10 +426,27 @@ public static List unwrapLoadBalancingConfigList(List> /** * Extracts the loadbalancer name from xds loadbalancer config. */ + // TODO(chengyuanzhang): delete after shifting to use bootstrap. public static String getBalancerNameFromXdsConfig(Map rawXdsConfig) { return JsonUtil.getString(rawXdsConfig, XDS_CONFIG_BALANCER_NAME_KEY); } + /** + * Extract the server name to use in EDS query. + */ + @Nullable + public static String getEdsServiceNameFromXdsConfig(Map rawXdsConfig) { + return JsonUtil.getString(rawXdsConfig, XDS_CONFIG_EDS_SERVICE_NAME); + } + + /** + * Extract the LRS server name to send load reports to. + */ + @Nullable + public static String getLrsServerNameFromXdsConfig(Map rawXdsConfig) { + return JsonUtil.getString(rawXdsConfig, XDS_CONFIG_LRS_SERVER_NAME); + } + /** * Extracts list of child policies from xds loadbalancer config. */ diff --git a/core/src/test/java/io/grpc/internal/ServiceConfigUtilTest.java b/core/src/test/java/io/grpc/internal/ServiceConfigUtilTest.java index 2753744298d..e7c0d402450 100644 --- a/core/src/test/java/io/grpc/internal/ServiceConfigUtilTest.java +++ b/core/src/test/java/io/grpc/internal/ServiceConfigUtilTest.java @@ -106,6 +106,60 @@ public void getFallbackPolicyFromXdsConfig_null() throws Exception { assertThat(fallbackPolicies).isNull(); } + @Test + public void getEdsServiceNameFromXdsConfig() throws Exception { + String rawLbConfig = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"childPolicy\" : [{\"round_robin\" : {}}, {\"lbPolicy2\" : {\"key\" : \"val\"}}]," + + "\"fallbackPolicy\" : [{\"lbPolicy3\" : {\"key\" : \"val\"}}, {\"lbPolicy4\" : {}}]," + + "\"edsServiceName\" : \"dns:///eds.service.com:8080\"" + + "}"; + + String edsServiceName = ServiceConfigUtil.getEdsServiceNameFromXdsConfig( + checkObject(JsonParser.parse(rawLbConfig))); + assertThat(edsServiceName).isEqualTo("dns:///eds.service.com:8080"); + } + + @Test + public void getEdsServiceNameFromXdsConfig_null() throws Exception { + String rawLbConfig = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"childPolicy\" : [{\"round_robin\" : {}}, {\"lbPolicy2\" : {\"key\" : \"val\"}}]," + + "\"fallbackPolicy\" : [{\"lbPolicy3\" : {\"key\" : \"val\"}}, {\"lbPolicy4\" : {}}]" + + "}"; + + String edsServiceName = ServiceConfigUtil.getEdsServiceNameFromXdsConfig( + checkObject(JsonParser.parse(rawLbConfig))); + assertThat(edsServiceName).isNull(); + } + + @Test + public void getLrsServerNameFromXdsConfig() throws Exception { + String rawLbConfig = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"childPolicy\" : [{\"round_robin\" : {}}, {\"lbPolicy2\" : {\"key\" : \"val\"}}]," + + "\"fallbackPolicy\" : [{\"lbPolicy3\" : {\"key\" : \"val\"}}, {\"lbPolicy4\" : {}}]," + + "\"lrsLoadReportingServerName\" : \"dns:///lrs.service.com:8080\"" + + "}"; + + String lrsServerName = ServiceConfigUtil.getLrsServerNameFromXdsConfig( + checkObject(JsonParser.parse(rawLbConfig))); + assertThat(lrsServerName).isEqualTo("dns:///lrs.service.com:8080"); + } + + @Test + public void getLrsServerNameFromXdsConfig_null() throws Exception { + String rawLbConfig = "{" + + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + + "\"childPolicy\" : [{\"round_robin\" : {}}, {\"lbPolicy2\" : {\"key\" : \"val\"}}]," + + "\"fallbackPolicy\" : [{\"lbPolicy3\" : {\"key\" : \"val\"}}, {\"lbPolicy4\" : {}}]" + + "}"; + + String lrsServerName = ServiceConfigUtil.getLrsServerNameFromXdsConfig( + checkObject(JsonParser.parse(rawLbConfig))); + assertThat(lrsServerName).isNull(); + } + @Test public void unwrapLoadBalancingConfig() throws Exception { String lbConfig = "{\"xds_experimental\" : { " diff --git a/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java b/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java index 7d1316cdec2..ce9a13335ab 100644 --- a/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java +++ b/xds/src/main/java/io/grpc/xds/XdsLoadBalancerProvider.java @@ -82,7 +82,13 @@ static ConfigOrError parseLoadBalancingConfigPolicy( ServiceConfigUtil.getBalancerNameFromXdsConfig(rawLoadBalancingPolicyConfig); LbConfig childPolicy = selectChildPolicy(rawLoadBalancingPolicyConfig, registry); LbConfig fallbackPolicy = selectFallbackPolicy(rawLoadBalancingPolicyConfig, registry); - return ConfigOrError.fromConfig(new XdsConfig(newBalancerName, childPolicy, fallbackPolicy)); + String edsServiceName = + ServiceConfigUtil.getEdsServiceNameFromXdsConfig(rawLoadBalancingPolicyConfig); + String lrsServerName = + ServiceConfigUtil.getLrsServerNameFromXdsConfig(rawLoadBalancingPolicyConfig); + return ConfigOrError.fromConfig( + new XdsConfig( + newBalancerName, childPolicy, fallbackPolicy, edsServiceName, lrsServerName)); } catch (RuntimeException e) { return ConfigOrError.fromError( Status.UNKNOWN.withDescription("Failed to parse config " + e.getMessage()).withCause(e)); @@ -126,18 +132,31 @@ private static LbConfig selectSupportedLbPolicy( * Represents a successfully parsed and validated LoadBalancingConfig for XDS. */ static final class XdsConfig { + // TODO(chengyuanzhang): delete after shifting to use bootstrap. final String balancerName; // TODO(carl-mastrangelo): make these Object's containing the fully parsed child configs. @Nullable final LbConfig childPolicy; @Nullable final LbConfig fallbackPolicy; + // Optional. Name to use in EDS query. If not present, defaults to the server name from the + // target URI. + @Nullable + final String edsServiceName; + // Optional. LRS server to send load reports to. If not present, load reporting will be + // disabled. If set to the empty string, load reporting will be sent to the same server that + // we obtained CDS data from. + @Nullable + final String lrsServerName; XdsConfig( - String balancerName, @Nullable LbConfig childPolicy, @Nullable LbConfig fallbackPolicy) { + String balancerName, @Nullable LbConfig childPolicy, @Nullable LbConfig fallbackPolicy, + @Nullable String edsServiceName, @Nullable String lrsServerName) { this.balancerName = checkNotNull(balancerName, "balancerName"); this.childPolicy = childPolicy; this.fallbackPolicy = fallbackPolicy; + this.edsServiceName = edsServiceName; + this.lrsServerName = lrsServerName; } @Override @@ -146,6 +165,8 @@ public String toString() { .add("balancerName", balancerName) .add("childPolicy", childPolicy) .add("fallbackPolicy", fallbackPolicy) + .add("edsServiceName", edsServiceName) + .add("lrsServerName", lrsServerName) .toString(); } @@ -157,12 +178,15 @@ public boolean equals(Object obj) { XdsConfig that = (XdsConfig) obj; return Objects.equal(this.balancerName, that.balancerName) && Objects.equal(this.childPolicy, that.childPolicy) - && Objects.equal(this.fallbackPolicy, that.fallbackPolicy); + && Objects.equal(this.fallbackPolicy, that.fallbackPolicy) + && Objects.equal(this.edsServiceName, that.edsServiceName) + && Objects.equal(this.lrsServerName, that.lrsServerName); } @Override public int hashCode() { - return Objects.hashCode(balancerName, childPolicy, fallbackPolicy); + return Objects.hashCode( + balancerName, childPolicy, fallbackPolicy, edsServiceName, lrsServerName); } } } diff --git a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerProviderTest.java b/xds/src/test/java/io/grpc/xds/XdsLoadBalancerProviderTest.java index 8451f0b6583..a5f38de78fa 100644 --- a/xds/src/test/java/io/grpc/xds/XdsLoadBalancerProviderTest.java +++ b/xds/src/test/java/io/grpc/xds/XdsLoadBalancerProviderTest.java @@ -161,7 +161,9 @@ public void parseLoadBalancingConfigPolicy() throws Exception { + "\"balancerName\" : \"dns:///balancer.example.com:8080\"," + "\"childPolicy\" : [{\"lbPolicy3\" : {\"key\" : \"val\"}}, {\"supported_1\" : {}}]," + "\"fallbackPolicy\" : [{\"unsupported\" : {}}, {\"round_robin\" : {\"key\" : \"val\"}}," - + "{\"supported_2\" : {\"key\" : \"val\"}}]" + + "{\"supported_2\" : {\"key\" : \"val\"}}]," + + "\"edsServiceName\" : \"dns:///eds.service.com:8080\"," + + "\"lrsLoadReportingServerName\" : \"dns:///lrs.service.com:8080\"" + "}"; Map rawlbConfigMap = checkObject(JsonParser.parse(rawLbConfig)); ConfigOrError configOrError = @@ -175,7 +177,9 @@ public void parseLoadBalancingConfigPolicy() throws Exception { ServiceConfigUtil.unwrapLoadBalancingConfig( checkObject(JsonParser.parse("{\"supported_1\" : {}}"))), ServiceConfigUtil.unwrapLoadBalancingConfig( - checkObject(JsonParser.parse("{\"round_robin\" : {\"key\" : \"val\"}}")))) + checkObject(JsonParser.parse("{\"round_robin\" : {\"key\" : \"val\"}}"))), + "dns:///eds.service.com:8080", + "dns:///lrs.service.com:8080") ); } From ecbc5e4f478e050248adbc24e0e5ac6a96fa5422 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Fri, 18 Oct 2019 16:30:48 -0700 Subject: [PATCH 111/131] stub: add RunWith for AbstractStub tests (#6304) --- stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java | 3 +++ stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java index 3cb13e9b368..0277b7a66ca 100644 --- a/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java +++ b/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java @@ -27,7 +27,10 @@ import io.grpc.stub.AbstractStub.StubFactory; import io.grpc.stub.ClientCalls.StubType; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +@RunWith(JUnit4.class) public class AbstractAsyncStubTest extends BaseAbstractStubTest { @Override diff --git a/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java index c7afe3f77bd..0c0fdaac91f 100644 --- a/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java +++ b/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java @@ -27,7 +27,10 @@ import io.grpc.stub.AbstractStub.StubFactory; import io.grpc.stub.ClientCalls.StubType; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +@RunWith(JUnit4.class) public class AbstractFutureStubTest extends BaseAbstractStubTest { @Override From ae11b9facc91f1b1d5282a4755c732317df943e9 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Fri, 18 Oct 2019 17:30:00 -0700 Subject: [PATCH 112/131] api,core,stub: fix lint errors (#6305) --- .../main/java/io/grpc/MethodDescriptor.java | 1 - .../io/grpc/internal/DnsNameResolver.java | 1 - .../io/grpc/internal/ServiceConfigUtil.java | 3 --- .../io/grpc/stub/BaseAbstractStubTest.java | 20 ++++++++++++++----- .../java/io/grpc/stub/ClientCallsTest.java | 8 ++++---- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/io/grpc/MethodDescriptor.java b/api/src/main/java/io/grpc/MethodDescriptor.java index 6e3c42918db..2c55af4905f 100644 --- a/api/src/main/java/io/grpc/MethodDescriptor.java +++ b/api/src/main/java/io/grpc/MethodDescriptor.java @@ -490,7 +490,6 @@ public Builder setRequestMarshaller(Marshaller requestMarshal * @param responseMarshaller the marshaller to use. * @since 1.1.0 */ - @SuppressWarnings("unchecked") public Builder setResponseMarshaller(Marshaller responseMarshaller) { this.responseMarshaller = responseMarshaller; return this; diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolver.java b/core/src/main/java/io/grpc/internal/DnsNameResolver.java index b85dd79ccb9..feb6d7d7767 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolver.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolver.java @@ -451,7 +451,6 @@ static ResolutionResults resolveAll( * * @throws IOException if one of the txt records contains improperly formatted JSON. */ - @SuppressWarnings("unchecked") @VisibleForTesting static List> parseTxtResults(List txtRecords) throws IOException { List> possibleServiceConfigChoices = new ArrayList<>(); diff --git a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java index 71e43b00866..96a7b039c5f 100644 --- a/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java +++ b/core/src/main/java/io/grpc/internal/ServiceConfigUtil.java @@ -355,7 +355,6 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC /** * Extracts load balancing configs from a service config. */ - @SuppressWarnings("unchecked") @VisibleForTesting public static List> getLoadBalancingConfigsFromServiceConfig( Map serviceConfig) { @@ -400,7 +399,6 @@ static Integer getMaxResponseMessageBytesFromMethodConfig(Map methodC * (map) with exactly one entry, where the key is the policy name and the value is a config object * for that policy. */ - @SuppressWarnings("unchecked") public static LbConfig unwrapLoadBalancingConfig(Map lbConfig) { if (lbConfig.size() != 1) { throw new RuntimeException( @@ -414,7 +412,6 @@ public static LbConfig unwrapLoadBalancingConfig(Map lbConfig) { /** * Given a JSON list of LoadBalancingConfigs, and convert it into a list of LbConfig. */ - @SuppressWarnings("unchecked") public static List unwrapLoadBalancingConfigList(List> list) { ArrayList result = new ArrayList<>(); for (Map rawChildPolicy : list) { diff --git a/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java b/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java index e2219b9ef67..b197c78aca2 100644 --- a/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java +++ b/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.mockito.Mockito.mock; import io.grpc.CallOptions; @@ -48,15 +49,24 @@ T create(Channel channel) { abstract T create(@Nullable Channel channel, @Nullable CallOptions callOptions); - @Test(expected = NullPointerException.class) + @Test public void callOptionsMustNotBeNull() { - create(channel, null); - throw new NullPointerException(); + try { + create(channel, null); + fail("NullPointerException expected"); + } catch (NullPointerException npe) { + // expected + } } - @Test(expected = NullPointerException.class) + @Test public void channelMustNotBeNull2() { - create(null, CallOptions.DEFAULT); + try { + create(null, CallOptions.DEFAULT); + fail("NullPointerException expected"); + } catch (NullPointerException npe) { + // expected + } } @Test diff --git a/stub/src/test/java/io/grpc/stub/ClientCallsTest.java b/stub/src/test/java/io/grpc/stub/ClientCallsTest.java index 9e70fb17658..bcae5340a2c 100644 --- a/stub/src/test/java/io/grpc/stub/ClientCallsTest.java +++ b/stub/src/test/java/io/grpc/stub/ClientCallsTest.java @@ -134,9 +134,9 @@ public void onCompleted() { }; ClientCalls.asyncUnaryCall(call, req, responseObserver); - assertThat(actualResponse.size()).isEqualTo(1); + assertThat(actualResponse).hasSize(1); assertEquals(resp, actualResponse.get(0)); - assertThat(completed.size()).isEqualTo(1); + assertThat(completed).hasSize(1); assertThat(completed.get(0)).isTrue(); } @@ -173,7 +173,7 @@ public void onCompleted() { }; ClientCalls.asyncUnaryCall(call, req, responseObserver); - assertThat(expected.size()).isEqualTo(1); + assertThat(expected).hasSize(1); assertThat(expected.get(0)).hasMessageThat() .isEqualTo("INTERNAL: Response message is null for unary call"); } @@ -212,7 +212,7 @@ public void onCompleted() { }; ClientCalls.asyncUnaryCall(call, req, responseObserver); - assertThat(expected.size()).isEqualTo(1); + assertThat(expected).hasSize(1); assertThat(expected.get(0)).hasMessageThat().isEqualTo("INTERNAL: Unique status"); } From 5cb67d6399d1717920934c0f8e13f039fac2bc19 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Mon, 21 Oct 2019 14:24:17 -0700 Subject: [PATCH 113/131] xds: remove invalid srcDir third_party/protoc-gen-validate/src/main/proto The directory third_party/protoc-gen-validate/src/main/proto was removed in #6177. --- xds/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/xds/build.gradle b/xds/build.gradle index 322529b8ef1..057fad2dec8 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -50,7 +50,6 @@ sourceSets { proto { srcDir 'third_party/envoy/src/main/proto' srcDir 'third_party/gogoproto/src/main/proto' - srcDir 'third_party/protoc-gen-validate/src/main/proto' srcDir 'third_party/udpa/src/main/proto' } } From f07fcd7d7bb2827df7b602b91991c9015ce7a02a Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Mon, 21 Oct 2019 15:07:35 -0700 Subject: [PATCH 114/131] xds: TlsContextManager refactoring to match its usage; add tests for TlsContextManager (#6297) --- .../SslContextSecretVolumeSecretProvider.java | 73 +++++++-- .../io/grpc/xds/sds/TlsContextManager.java | 30 ++-- .../xds/sds/trust/SdsTrustManagerFactory.java | 29 ++-- ...ContextSecretVolumeSecretProviderTest.java | 150 ++++++++++++------ .../grpc/xds/sds/TlsContextManagerTest.java | 57 +++++++ .../sds/trust/SdsTrustManagerFactoryTest.java | 26 +-- 6 files changed, 265 insertions(+), 100 deletions(-) create mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsContextManagerTest.java diff --git a/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java index 5a7dc2e2447..d104a0a184c 100644 --- a/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java +++ b/xds/src/main/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProvider.java @@ -18,20 +18,28 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.auth.CommonTlsContext; +import io.envoyproxy.envoy.api.v2.auth.CommonTlsContext.ValidationContextTypeCase; +import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext; import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext; import io.envoyproxy.envoy.api.v2.core.DataSource.SpecifierCase; import io.grpc.netty.GrpcSslContexts; +import io.grpc.xds.sds.trust.SdsTrustManagerFactory; import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import java.io.File; +import java.io.IOException; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; import java.util.concurrent.Executor; import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nullable; -import javax.net.ssl.SSLException; /** * An SslContext provider that uses file-based secrets (secret volume). Used for both server and @@ -46,18 +54,18 @@ final class SslContextSecretVolumeSecretProvider implements SecretProvider 0) { + tlsCertificate = commonTlsContext.getTlsCertificates(0); + } // first validate validateTlsCertificate(tlsCertificate, /* optional= */ false); - // certContext exists in case of mTLS, else null for a server - if (certContext != null) { - certContext = validateCertificateContext(certContext, /* optional= */ true); + CertificateValidationContext certificateValidationContext = + getCertificateValidationContext(commonTlsContext); + // certificateValidationContext exists in case of mTLS, else null for a server + if (certificateValidationContext != null) { + certificateValidationContext = + validateCertificateContext(certificateValidationContext, /* optional= */ true); } String privateKeyPassword = tlsCertificate.hasPassword() ? tlsCertificate.getPassword().getInlineString() : null; - String trustedCa = certContext != null ? certContext.getTrustedCa().getFilename() : null; return new SslContextSecretVolumeSecretProvider( tlsCertificate.getPrivateKey().getFilename(), privateKeyPassword, tlsCertificate.getCertificateChain().getFilename(), - trustedCa, + certificateValidationContext, /* server= */ true); } static SslContextSecretVolumeSecretProvider getProviderForClient( - @Nullable TlsCertificate tlsCertificate, CertificateValidationContext certContext) { + UpstreamTlsContext upstreamTlsContext) { + checkNotNull(upstreamTlsContext, "upstreamTlsContext"); + CommonTlsContext commonTlsContext = upstreamTlsContext.getCommonTlsContext(); + CertificateValidationContext certificateValidationContext = + getCertificateValidationContext(commonTlsContext); // first validate - validateCertificateContext(certContext, /* optional= */ false); + validateCertificateContext(certificateValidationContext, /* optional= */ false); + TlsCertificate tlsCertificate = null; + if (commonTlsContext.getTlsCertificatesCount() > 0) { + tlsCertificate = commonTlsContext.getTlsCertificates(0); + } // tlsCertificate exists in case of mTLS, else null for a client if (tlsCertificate != null) { tlsCertificate = validateTlsCertificate(tlsCertificate, /* optional= */ true); @@ -139,10 +163,23 @@ static SslContextSecretVolumeSecretProvider getProviderForClient( privateKey, privateKeyPassword, certificateChain, - certContext.getTrustedCa().getFilename(), + certificateValidationContext, /* server= */ false); } + private static CertificateValidationContext getCertificateValidationContext( + CommonTlsContext commonTlsContext) { + checkNotNull(commonTlsContext, "commonTlsContext"); + ValidationContextTypeCase type = commonTlsContext.getValidationContextTypeCase(); + checkState( + type == ValidationContextTypeCase.VALIDATION_CONTEXT + || type == ValidationContextTypeCase.VALIDATIONCONTEXTTYPE_NOT_SET, + "incorrect ValidationContextTypeCase"); + return type == ValidationContextTypeCase.VALIDATION_CONTEXT + ? commonTlsContext.getValidationContext() + : null; + } + @Override public void addCallback(final Callback callback, Executor executor) { checkNotNull(callback, "callback"); @@ -170,17 +207,19 @@ public void run() { } @VisibleForTesting - SslContext buildSslContextFromSecrets() throws SSLException { + SslContext buildSslContextFromSecrets() + throws IOException, CertificateException, CertStoreException { SslContextBuilder sslContextBuilder; if (server) { sslContextBuilder = GrpcSslContexts.forServer( new File(certificateChain), new File(privateKey), privateKeyPassword); - if (trustedCa != null) { - sslContextBuilder.trustManager(new File(trustedCa)); + if (certContext != null) { + sslContextBuilder.trustManager(new SdsTrustManagerFactory(certContext)); } } else { - sslContextBuilder = GrpcSslContexts.forClient().trustManager(new File(trustedCa)); + sslContextBuilder = + GrpcSslContexts.forClient().trustManager(new SdsTrustManagerFactory(certContext)); if (privateKey != null && certificateChain != null) { sslContextBuilder.keyManager( new File(certificateChain), new File(privateKey), privateKeyPassword); diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java b/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java index 5d93a0bfd1a..8f7b8c0e704 100644 --- a/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java +++ b/xds/src/main/java/io/grpc/xds/sds/TlsContextManager.java @@ -25,27 +25,33 @@ * Class to manage secrets used to create SSL contexts - this effectively manages SSL contexts * (aka TlsContexts) based on inputs we get from xDS. This is used by gRPC-xds to access the * SSL contexts/secrets and is not public API. + * Currently it just creates a new SecretProvider for each call. */ +// TODO(sanjaypujare): implement a Map and ref-counting @Internal public final class TlsContextManager { - /** - * Finds an existing SecretProvider or creates it if it doesn't exist. - * Used for retrieving a server-side SslContext - */ + private static TlsContextManager instance; + + private TlsContextManager() {} + + /** Gets the ContextManager singleton. */ + public static synchronized TlsContextManager getInstance() { + if (instance == null) { + instance = new TlsContextManager(); + } + return instance; + } + + /** Creates a SecretProvider. Used for retrieving a server-side SslContext. */ public SecretProvider findOrCreateServerSslContextProvider( DownstreamTlsContext downstreamTlsContext) { - // TODO(sanjaypujare): implementation of SecretProvider - return null; + return SslContextSecretVolumeSecretProvider.getProviderForServer(downstreamTlsContext); } - /** - * Finds an existing SecretProvider or creates it if it doesn't exist. - * Used for retrieving a client-side SslContext - */ + /** Creates a SecretProvider. Used for retrieving a client-side SslContext. */ public SecretProvider findOrCreateClientSslContextProvider( UpstreamTlsContext upstreamTlsContext) { - // TODO(sanjaypujare): implementation of SecretProvider - return null; + return SslContextSecretVolumeSecretProvider.getProviderForClient(upstreamTlsContext); } } diff --git a/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java b/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java index 2e6edc6b370..6db7b7ac03f 100644 --- a/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java +++ b/xds/src/main/java/io/grpc/xds/sds/trust/SdsTrustManagerFactory.java @@ -16,9 +16,13 @@ package io.grpc.xds.sds.trust; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import com.google.common.base.Strings; import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.core.DataSource.SpecifierCase; import io.grpc.Internal; import io.netty.handler.ssl.util.SimpleTrustManagerFactory; import java.io.File; @@ -31,7 +35,6 @@ import java.security.cert.X509Certificate; import java.util.logging.Level; import java.util.logging.Logger; -import javax.annotation.Nullable; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; @@ -47,19 +50,23 @@ public final class SdsTrustManagerFactory extends SimpleTrustManagerFactory { private static final Logger logger = Logger.getLogger(SdsTrustManagerFactory.class.getName()); private SdsX509TrustManager sdsX509TrustManager; - /** Constructor that loads certs from a file. */ - public SdsTrustManagerFactory( - String certsFile, @Nullable CertificateValidationContext certContext) + /** Constructor constructs from a {@link CertificateValidationContext}. */ + public SdsTrustManagerFactory(CertificateValidationContext certificateValidationContext) throws CertificateException, IOException, CertStoreException { - this(CertificateUtils.toX509Certificates(new File(certsFile)), certContext); + checkNotNull(certificateValidationContext, "certificateValidationContext"); + String certsFile = getTrustedCaFromCertContext(certificateValidationContext); + checkState(!Strings.isNullOrEmpty(certsFile), + "trustedCa.file-name in certificateValidationContext cannot be empty"); + createSdsX509TrustManager( + CertificateUtils.toX509Certificates(new File(certsFile)), certificateValidationContext); } - /** Constructor that takes array of certs. */ - public SdsTrustManagerFactory( - X509Certificate[] certs, @Nullable CertificateValidationContext certContext) - throws CertStoreException { - checkNotNull(certs, "certs"); - createSdsX509TrustManager(certs, certContext); + private static String getTrustedCaFromCertContext( + CertificateValidationContext certificateValidationContext) { + checkArgument( + certificateValidationContext.getTrustedCa().getSpecifierCase() == SpecifierCase.FILENAME, + "filename expected"); + return certificateValidationContext.getTrustedCa().getFilename(); } private void createSdsX509TrustManager( diff --git a/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java b/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java index 1510cc6fcd9..b1607c773f1 100644 --- a/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/SslContextSecretVolumeSecretProviderTest.java @@ -18,13 +18,19 @@ import static com.google.common.truth.Truth.assertThat; +import com.google.common.base.Strings; import com.google.common.util.concurrent.MoreExecutors; import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.auth.CommonTlsContext; +import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext; import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; +import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext; import io.envoyproxy.envoy.api.v2.core.DataSource; import io.grpc.internal.testing.TestUtils; import io.netty.handler.ssl.SslContext; import java.io.IOException; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; import java.util.List; import org.junit.Assert; import org.junit.Rule; @@ -266,22 +272,12 @@ public void validateTlsCertificate_privateKeyInlineString_throwsException() { } } - @Test - public void getProviderForServer_nullTlsCertificate_throwsException() { - try { - SslContextSecretVolumeSecretProvider.getProviderForServer( - /* tlsCertificate= */ null, /* certContext= */ null); - Assert.fail("no exception thrown"); - } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessageThat().isEqualTo("tlsCertificate is required"); - } - } - @Test public void getProviderForServer_defaultTlsCertificate_throwsException() { TlsCertificate tlsCert = TlsCertificate.getDefaultInstance(); try { - SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, /* certContext= */ null); + SslContextSecretVolumeSecretProvider.getProviderForServer( + buildDownstreamTlsContext(getCommonTlsContext(tlsCert, /* certContext= */ null))); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessageThat().isEqualTo("filename expected"); @@ -300,30 +296,20 @@ public void getProviderForServer_certContextWithInlineString_throwsException() { .setTrustedCa(DataSource.newBuilder().setInlineString("foo")) .build(); try { - SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, certContext); + SslContextSecretVolumeSecretProvider.getProviderForServer( + buildDownstreamTlsContext(getCommonTlsContext(tlsCert, certContext))); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { assertThat(expected.getMessage()).isEqualTo("filename expected"); } } - @Test - public void getProviderForClient_nullCertContext_throwsException() { - try { - SslContextSecretVolumeSecretProvider.getProviderForClient( - /* tlsCertificate= */ null, /* certContext= */ null); - Assert.fail("no exception thrown"); - } catch (IllegalArgumentException expected) { - assertThat(expected).hasMessageThat().isEqualTo("certContext is required"); - } - } - @Test public void getProviderForClient_defaultCertContext_throwsException() { CertificateValidationContext certContext = CertificateValidationContext.getDefaultInstance(); try { SslContextSecretVolumeSecretProvider.getProviderForClient( - /* tlsCertificate= */ null, certContext); + buildUpstreamTlsContext(getCommonTlsContext(/* tlsCertificate= */ null, certContext))); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessageThat().isEqualTo("certContext is required"); @@ -342,7 +328,8 @@ public void getProviderForClient_certWithPrivateKeyInlineString_throwsException( .setTrustedCa(DataSource.newBuilder().setFilename("foo")) .build(); try { - SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); + SslContextSecretVolumeSecretProvider.getProviderForClient( + buildUpstreamTlsContext(getCommonTlsContext(tlsCert, certContext))); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessageThat().isEqualTo("filename expected"); @@ -361,7 +348,8 @@ public void getProviderForClient_certWithCertChainInlineString_throwsException() .setTrustedCa(DataSource.newBuilder().setFilename("foo")) .build(); try { - SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); + SslContextSecretVolumeSecretProvider.getProviderForClient( + buildUpstreamTlsContext(getCommonTlsContext(tlsCert, certContext))); Assert.fail("no exception thrown"); } catch (IllegalArgumentException expected) { assertThat(expected).hasMessageThat().isEqualTo("filename expected"); @@ -387,24 +375,13 @@ private static SslContextSecretVolumeSecretProvider getSslContextSecretVolumeSec if (trustedCaFilename != null) { trustedCaFilename = getTempFileNameForResourcesFile(trustedCaFilename); } - - TlsCertificate tlsCert = - (certChainFilename == null && privateKeyFilename == null) - ? null - : TlsCertificate.newBuilder() - .setCertificateChain(DataSource.newBuilder().setFilename(certChainFilename)) - .setPrivateKey(DataSource.newBuilder().setFilename(privateKeyFilename)) - .build(); - CertificateValidationContext certContext = - trustedCaFilename == null - ? null - : CertificateValidationContext.newBuilder() - .setTrustedCa(DataSource.newBuilder().setFilename(trustedCaFilename)) - .build(); - return server - ? SslContextSecretVolumeSecretProvider.getProviderForServer(tlsCert, certContext) - : SslContextSecretVolumeSecretProvider.getProviderForClient(tlsCert, certContext); + ? SslContextSecretVolumeSecretProvider.getProviderForServer( + buildDownstreamTlsContextFromFilenames( + privateKeyFilename, certChainFilename, trustedCaFilename)) + : SslContextSecretVolumeSecretProvider.getProviderForClient( + buildUpstreamTlsContextFromFilenames( + privateKeyFilename, certChainFilename, trustedCaFilename)); } /** @@ -412,7 +389,8 @@ private static SslContextSecretVolumeSecretProvider getSslContextSecretVolumeSec * check returned SslContext. */ private static void sslContextForEitherWithBothCertAndTrust( - boolean server, String pemFile, String keyFile, String caFile) throws IOException { + boolean server, String pemFile, String keyFile, String caFile) + throws IOException, CertificateException, CertStoreException { SslContextSecretVolumeSecretProvider provider = getSslContextSecretVolumeSecretProvider(server, pemFile, keyFile, caFile); @@ -431,29 +409,100 @@ private static void doChecksOnSslContext(boolean server, SslContext sslContext) assertThat(apnProtos).contains("h2"); } + /** + * Helper method to build DownstreamTlsContext for above tests. Called from other classes as well. + */ + static DownstreamTlsContext buildDownstreamTlsContextFromFilenames( + String privateKey, String certChain, String trustCa) { + return buildDownstreamTlsContext( + buildCommonTlsContextFromFilenames(privateKey, certChain, trustCa)); + } + + /** + * Helper method to build UpstreamTlsContext for above tests. Called from other classes as well. + */ + static UpstreamTlsContext buildUpstreamTlsContextFromFilenames( + String privateKey, String certChain, String trustCa) { + return buildUpstreamTlsContext( + buildCommonTlsContextFromFilenames(privateKey, certChain, trustCa)); + } + + private static CommonTlsContext buildCommonTlsContextFromFilenames( + String privateKey, String certChain, String trustCa) { + TlsCertificate tlsCert = null; + if (!Strings.isNullOrEmpty(privateKey) && !Strings.isNullOrEmpty(certChain)) { + tlsCert = + TlsCertificate.newBuilder() + .setCertificateChain(DataSource.newBuilder().setFilename(certChain)) + .setPrivateKey(DataSource.newBuilder().setFilename(privateKey)) + .build(); + } + CertificateValidationContext certContext = null; + if (!Strings.isNullOrEmpty(trustCa)) { + certContext = + CertificateValidationContext.newBuilder() + .setTrustedCa(DataSource.newBuilder().setFilename(trustCa)) + .build(); + } + return getCommonTlsContext(tlsCert, certContext); + } + + private static CommonTlsContext getCommonTlsContext( + TlsCertificate tlsCertificate, CertificateValidationContext certContext) { + CommonTlsContext.Builder builder = CommonTlsContext.newBuilder(); + if (tlsCertificate != null) { + builder = builder.addTlsCertificates(tlsCertificate); + } + if (certContext != null) { + builder = builder.setValidationContext(certContext); + } + return builder.build(); + } + + /** + * Helper method to build DownstreamTlsContext for above tests. Called from other classes as well. + */ + private static DownstreamTlsContext buildDownstreamTlsContext(CommonTlsContext commonTlsContext) { + DownstreamTlsContext downstreamTlsContext = + DownstreamTlsContext.newBuilder().setCommonTlsContext(commonTlsContext).build(); + return downstreamTlsContext; + } + + /** + * Helper method to build UpstreamTlsContext for above tests. Called from other classes as well. + */ + private static UpstreamTlsContext buildUpstreamTlsContext(CommonTlsContext commonTlsContext) { + UpstreamTlsContext upstreamTlsContext = + UpstreamTlsContext.newBuilder().setCommonTlsContext(commonTlsContext).build(); + return upstreamTlsContext; + } + @Test - public void getProviderForServer() throws IOException { + public void getProviderForServer() throws IOException, CertificateException, CertStoreException { sslContextForEitherWithBothCertAndTrust( true, SERVER_1_PEM_FILE, SERVER_1_KEY_FILE, CA_PEM_FILE); } @Test - public void getProviderForClient() throws IOException { + public void getProviderForClient() throws IOException, CertificateException, CertStoreException { sslContextForEitherWithBothCertAndTrust(false, CLIENT_PEM_FILE, CLIENT_KEY_FILE, CA_PEM_FILE); } @Test - public void getProviderForServer_onlyCert() throws IOException { + public void getProviderForServer_onlyCert() + throws IOException, CertificateException, CertStoreException { sslContextForEitherWithBothCertAndTrust(true, SERVER_1_PEM_FILE, SERVER_1_KEY_FILE, null); } @Test - public void getProviderForClient_onlyTrust() throws IOException { + public void getProviderForClient_onlyTrust() + throws IOException, CertificateException, CertStoreException { sslContextForEitherWithBothCertAndTrust(false, null, null, CA_PEM_FILE); } @Test - public void getProviderForServer_badFile_throwsException() throws IOException { + public void getProviderForServer_badFile_throwsException() + throws IOException, CertificateException, CertStoreException { try { sslContextForEitherWithBothCertAndTrust(true, SERVER_1_PEM_FILE, SERVER_1_PEM_FILE, null); Assert.fail("no exception thrown"); @@ -509,6 +558,7 @@ public void getProviderForClient_both_callsback() throws IOException { doChecksOnSslContext(false, testCallback.updatedSecret); } + // note this test generates stack-trace but can be safely ignored @Test public void getProviderForClient_both_callsback_setException() throws IOException { SslContextSecretVolumeSecretProvider provider = diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsContextManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsContextManagerTest.java new file mode 100644 index 00000000000..9adcd3bcd81 --- /dev/null +++ b/xds/src/test/java/io/grpc/xds/sds/TlsContextManagerTest.java @@ -0,0 +1,57 @@ +/* + * Copyright 2019 The gRPC Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.grpc.xds.sds; + +import static com.google.common.truth.Truth.assertThat; + +import io.envoyproxy.envoy.api.v2.auth.DownstreamTlsContext; +import io.envoyproxy.envoy.api.v2.auth.UpstreamTlsContext; +import io.netty.handler.ssl.SslContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link TlsContextManager}. */ +@RunWith(JUnit4.class) +public class TlsContextManagerTest { + + private static final String SERVER_1_PEM_FILE = "server1.pem"; + private static final String SERVER_1_KEY_FILE = "server1.key"; + private static final String CA_PEM_FILE = "ca.pem"; + + @Test + public void createServerSslContextProvider() { + DownstreamTlsContext downstreamTlsContext = + SslContextSecretVolumeSecretProviderTest.buildDownstreamTlsContextFromFilenames( + SERVER_1_KEY_FILE, SERVER_1_PEM_FILE, /* trustCa= */ null); + + SecretProvider serverSecretProvider = + TlsContextManager.getInstance().findOrCreateServerSslContextProvider(downstreamTlsContext); + assertThat(serverSecretProvider).isNotNull(); + } + + @Test + public void createClientSslContextProvider() { + UpstreamTlsContext upstreamTlsContext = + SslContextSecretVolumeSecretProviderTest.buildUpstreamTlsContextFromFilenames( + /* privateKey= */ null, /* certChain= */ null, CA_PEM_FILE); + + SecretProvider serverSecretProvider = + TlsContextManager.getInstance().findOrCreateClientSslContextProvider(upstreamTlsContext); + assertThat(serverSecretProvider).isNotNull(); + } +} diff --git a/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java b/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java index e6eabcbb553..9f1565045bc 100644 --- a/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java +++ b/xds/src/test/java/io/grpc/xds/sds/trust/SdsTrustManagerFactoryTest.java @@ -18,6 +18,8 @@ import static com.google.common.truth.Truth.assertThat; +import io.envoyproxy.envoy.api.v2.auth.CertificateValidationContext; +import io.envoyproxy.envoy.api.v2.core.DataSource; import io.grpc.internal.testing.TestUtils; import java.io.IOException; import java.security.cert.CertStoreException; @@ -51,8 +53,7 @@ public class SdsTrustManagerFactoryTest { @Test public void constructor_fromFile() throws CertificateException, IOException, CertStoreException { SdsTrustManagerFactory factory = - new SdsTrustManagerFactory( - TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + new SdsTrustManagerFactory(getCertContextFromPath(CA_PEM_FILE)); assertThat(factory).isNotNull(); TrustManager[] tms = factory.getTrustManagers(); assertThat(tms).isNotNull(); @@ -72,8 +73,7 @@ public void constructor_fromFile() throws CertificateException, IOException, Cer public void checkServerTrusted_goodCert() throws CertificateException, IOException, CertStoreException { SdsTrustManagerFactory factory = - new SdsTrustManagerFactory( - TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + new SdsTrustManagerFactory(getCertContextFromPath(CA_PEM_FILE)); SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; X509Certificate[] serverChain = CertificateUtils.toX509Certificates(TestUtils.loadCert(SERVER_1_PEM_FILE)); @@ -84,8 +84,7 @@ public void checkServerTrusted_goodCert() public void checkClientTrusted_goodCert() throws CertificateException, IOException, CertStoreException { SdsTrustManagerFactory factory = - new SdsTrustManagerFactory( - TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + new SdsTrustManagerFactory(getCertContextFromPath(CA_PEM_FILE)); SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; X509Certificate[] clientChain = CertificateUtils.toX509Certificates(TestUtils.loadCert(CLIENT_PEM_FILE)); @@ -96,8 +95,7 @@ public void checkClientTrusted_goodCert() public void checkServerTrusted_badCert_throwsException() throws CertificateException, IOException, CertStoreException { SdsTrustManagerFactory factory = - new SdsTrustManagerFactory( - TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + new SdsTrustManagerFactory(getCertContextFromPath(CA_PEM_FILE)); SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; X509Certificate[] serverChain = CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_SERVER_PEM_FILE)); @@ -115,8 +113,7 @@ public void checkServerTrusted_badCert_throwsException() public void checkClientTrusted_badCert_throwsException() throws CertificateException, IOException, CertStoreException { SdsTrustManagerFactory factory = - new SdsTrustManagerFactory( - TestUtils.loadCert(CA_PEM_FILE).getAbsolutePath(), /* certContext= */ null); + new SdsTrustManagerFactory(getCertContextFromPath(CA_PEM_FILE)); SdsX509TrustManager sdsX509TrustManager = (SdsX509TrustManager) factory.getTrustManagers()[0]; X509Certificate[] clientChain = CertificateUtils.toX509Certificates(TestUtils.loadCert(BAD_CLIENT_PEM_FILE)); @@ -129,4 +126,13 @@ public void checkClientTrusted_badCert_throwsException() .contains("unable to find valid certification path to requested target"); } } + + /** constructs CertificateValidationContext from the resources file-path. */ + private static final CertificateValidationContext getCertContextFromPath(String pemFilePath) + throws IOException { + return CertificateValidationContext.newBuilder() + .setTrustedCa( + DataSource.newBuilder().setFilename(TestUtils.loadCert(pemFilePath).getAbsolutePath())) + .build(); + } } From 13fad99549c85632ee523825f935c8721279ca1b Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Mon, 21 Oct 2019 15:42:27 -0700 Subject: [PATCH 115/131] xds: remove gogoproto dependency Since https://github.com/envoyproxy/envoy/commit/e7f0b7176efdc65f96eb1697b829d1e6187f4502 and https://github.com/grpc/grpc-java/commit/1dd72ab043b7596e9ecff59fb3a666e4480e738e , gogoproto is not a dependency anymore. --- NOTICE.txt | 11 -- xds/build.gradle | 2 - xds/third_party/gogoproto/LICENSE | 35 ----- xds/third_party/gogoproto/import.sh | 49 ------ .../src/main/proto/gogoproto/gogo.proto | 144 ------------------ 5 files changed, 241 deletions(-) delete mode 100644 xds/third_party/gogoproto/LICENSE delete mode 100755 xds/third_party/gogoproto/import.sh delete mode 100644 xds/third_party/gogoproto/src/main/proto/gogoproto/gogo.proto diff --git a/NOTICE.txt b/NOTICE.txt index e8792776057..ebf6f4d9580 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -38,17 +38,6 @@ obtained at: * LOCATION_IN_GRPC: * xds/third_party/envoy -This product contains a modified portion of 'gogoprotobuf', -an open source Protocol Buffers support for Go with Gadgets, -which can be obtained at: - - * LICENSE: - * xds/third_party/gogoproto/LICENSE - * HOMEPAGE: - * https://github.com/gogo/protobuf - * LOCATION_IN_GRPC: - * xds/third_party/gogoproto - This product contains a modified portion of 'udpa', an open source universal data plane API, which can be obtained at: diff --git a/xds/build.gradle b/xds/build.gradle index 057fad2dec8..f4d452869f3 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -49,7 +49,6 @@ sourceSets { main { proto { srcDir 'third_party/envoy/src/main/proto' - srcDir 'third_party/gogoproto/src/main/proto' srcDir 'third_party/udpa/src/main/proto' } } @@ -68,7 +67,6 @@ shadowJar { include(dependency('io.envoyproxy.protoc-gen-validate:')) } relocate 'com.github.udpa', 'io.grpc.xds.shaded.com.github.udpa' - relocate 'com.google.protobuf.GoGoProtos', 'io.grpc.xds.shaded.gogoproto.GoGoProtos' relocate 'io.envoyproxy', 'io.grpc.xds.shaded.io.envoyproxy' relocate 'io.grpc.netty', 'io.grpc.netty.shaded.io.grpc.netty' relocate 'io.netty', 'io.grpc.netty.shaded.io.netty' diff --git a/xds/third_party/gogoproto/LICENSE b/xds/third_party/gogoproto/LICENSE deleted file mode 100644 index f57de90da8a..00000000000 --- a/xds/third_party/gogoproto/LICENSE +++ /dev/null @@ -1,35 +0,0 @@ -Copyright (c) 2013, The GoGo Authors. All rights reserved. - -Protocol Buffers for Go with Gadgets - -Go support for Protocol Buffers - Google's data interchange format - -Copyright 2010 The Go Authors. All rights reserved. -https://github.com/golang/protobuf - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - diff --git a/xds/third_party/gogoproto/import.sh b/xds/third_party/gogoproto/import.sh deleted file mode 100755 index 5ffb4da6190..00000000000 --- a/xds/third_party/gogoproto/import.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash -# Copyright 2019 The gRPC Authors -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Update BRANCH then in this directory run ./import.sh - -set -e -BRANCH=v1.2.0 -GIT_REPO="https://github.com/gogo/protobuf.git" -GIT_BASE_DIR=protobuf -SOURCE_PROTO_BASE_DIR=protobuf -TARGET_PROTO_BASE_DIR=src/main/proto -FILES=( -gogoproto/gogo.proto -) - -# clone the gogoproto github repo in a tmp directory -tmpdir="$(mktemp -d)" -pushd "${tmpdir}" -rm -rf "$GIT_BASE_DIR" -git clone -b $BRANCH $GIT_REPO -cd "$GIT_BASE_DIR" -popd - -cp -p "${tmpdir}/${GIT_BASE_DIR}/LICENSE" LICENSE - -mkdir -p "${TARGET_PROTO_BASE_DIR}" -pushd "${TARGET_PROTO_BASE_DIR}" - -# copy proto files to project directory -for file in "${FILES[@]}" -do - mkdir -p "$(dirname "${file}")" - cp -p "${tmpdir}/${SOURCE_PROTO_BASE_DIR}/${file}" "${file}" -done -popd - -rm -rf "$tmpdir" diff --git a/xds/third_party/gogoproto/src/main/proto/gogoproto/gogo.proto b/xds/third_party/gogoproto/src/main/proto/gogoproto/gogo.proto deleted file mode 100644 index b80c85653f7..00000000000 --- a/xds/third_party/gogoproto/src/main/proto/gogoproto/gogo.proto +++ /dev/null @@ -1,144 +0,0 @@ -// Protocol Buffers for Go with Gadgets -// -// Copyright (c) 2013, The GoGo Authors. All rights reserved. -// http://github.com/gogo/protobuf -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto2"; -package gogoproto; - -import "google/protobuf/descriptor.proto"; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "GoGoProtos"; -option go_package = "github.com/gogo/protobuf/gogoproto"; - -extend google.protobuf.EnumOptions { - optional bool goproto_enum_prefix = 62001; - optional bool goproto_enum_stringer = 62021; - optional bool enum_stringer = 62022; - optional string enum_customname = 62023; - optional bool enumdecl = 62024; -} - -extend google.protobuf.EnumValueOptions { - optional string enumvalue_customname = 66001; -} - -extend google.protobuf.FileOptions { - optional bool goproto_getters_all = 63001; - optional bool goproto_enum_prefix_all = 63002; - optional bool goproto_stringer_all = 63003; - optional bool verbose_equal_all = 63004; - optional bool face_all = 63005; - optional bool gostring_all = 63006; - optional bool populate_all = 63007; - optional bool stringer_all = 63008; - optional bool onlyone_all = 63009; - - optional bool equal_all = 63013; - optional bool description_all = 63014; - optional bool testgen_all = 63015; - optional bool benchgen_all = 63016; - optional bool marshaler_all = 63017; - optional bool unmarshaler_all = 63018; - optional bool stable_marshaler_all = 63019; - - optional bool sizer_all = 63020; - - optional bool goproto_enum_stringer_all = 63021; - optional bool enum_stringer_all = 63022; - - optional bool unsafe_marshaler_all = 63023; - optional bool unsafe_unmarshaler_all = 63024; - - optional bool goproto_extensions_map_all = 63025; - optional bool goproto_unrecognized_all = 63026; - optional bool gogoproto_import = 63027; - optional bool protosizer_all = 63028; - optional bool compare_all = 63029; - optional bool typedecl_all = 63030; - optional bool enumdecl_all = 63031; - - optional bool goproto_registration = 63032; - optional bool messagename_all = 63033; - - optional bool goproto_sizecache_all = 63034; - optional bool goproto_unkeyed_all = 63035; -} - -extend google.protobuf.MessageOptions { - optional bool goproto_getters = 64001; - optional bool goproto_stringer = 64003; - optional bool verbose_equal = 64004; - optional bool face = 64005; - optional bool gostring = 64006; - optional bool populate = 64007; - optional bool stringer = 67008; - optional bool onlyone = 64009; - - optional bool equal = 64013; - optional bool description = 64014; - optional bool testgen = 64015; - optional bool benchgen = 64016; - optional bool marshaler = 64017; - optional bool unmarshaler = 64018; - optional bool stable_marshaler = 64019; - - optional bool sizer = 64020; - - optional bool unsafe_marshaler = 64023; - optional bool unsafe_unmarshaler = 64024; - - optional bool goproto_extensions_map = 64025; - optional bool goproto_unrecognized = 64026; - - optional bool protosizer = 64028; - optional bool compare = 64029; - - optional bool typedecl = 64030; - - optional bool messagename = 64033; - - optional bool goproto_sizecache = 64034; - optional bool goproto_unkeyed = 64035; -} - -extend google.protobuf.FieldOptions { - optional bool nullable = 65001; - optional bool embed = 65002; - optional string customtype = 65003; - optional string customname = 65004; - optional string jsontag = 65005; - optional string moretags = 65006; - optional string casttype = 65007; - optional string castkey = 65008; - optional string castvalue = 65009; - - optional bool stdtime = 65010; - optional bool stdduration = 65011; - optional bool wktpointer = 65012; - -} From ed845991dbb39401425d85e9aa6289afa5db5374 Mon Sep 17 00:00:00 2001 From: sanjaypujare Date: Mon, 21 Oct 2019 16:45:45 -0700 Subject: [PATCH 116/131] xds: remove unused SecretManager code based on separate TlsCertificate and CertificateValidationContext secrets (#6310) --- .../java/io/grpc/xds/sds/SecretManager.java | 54 ------- .../io/grpc/xds/sds/SecretProviderMap.java | 61 -------- .../sds/TlsCertificateSecretProviderMap.java | 36 ----- ...CertificateSecretVolumeSecretProvider.java | 89 ----------- .../io/grpc/xds/sds/TlsCertificateStore.java | 92 ----------- .../io/grpc/xds/sds/SecretManagerTest.java | 77 --------- .../TlsCertificateSecretProviderMapTest.java | 100 ------------ ...ificateSecretVolumeSecretProviderTest.java | 147 ------------------ .../grpc/xds/sds/TlsCertificateStoreTest.java | 140 ----------------- 9 files changed, 796 deletions(-) delete mode 100644 xds/src/main/java/io/grpc/xds/sds/SecretManager.java delete mode 100644 xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java delete mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java delete mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java delete mode 100644 xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java delete mode 100644 xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java delete mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java delete mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java delete mode 100644 xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretManager.java b/xds/src/main/java/io/grpc/xds/sds/SecretManager.java deleted file mode 100644 index 45ad2b5ab9c..00000000000 --- a/xds/src/main/java/io/grpc/xds/sds/SecretManager.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.envoyproxy.envoy.api.v2.core.ConfigSource; -import io.grpc.Internal; - -/** - * SecretManager to manage secrets. This is used by gRPC-xds to access secrets - * and not part of the public API of gRPC - */ -// TODO(sanjaypujare): Lifecycle management for this manager and the {@link SecretProvider}s -// to be implemented using an object-pool mechanism -@Internal -public final class SecretManager { - - /** - * Finds an existing SecretProvider or creates it if it doesn't exist. - * - * @param configSource from the SdsSecretConfig - * @param name from the SdsSecretConfig - * @return the SecretProvider - */ - public SecretProvider findOrCreateTlsCertificateProvider( - ConfigSource configSource, String name) { - checkNotNull(configSource, "configSource"); - checkNotNull(name, "name"); - // for now we support only path/volume based secret provider - if (configSource.getConfigSourceSpecifierCase() - != ConfigSource.ConfigSourceSpecifierCase.PATH) { - throw new UnsupportedOperationException("Only file based secret supported"); - } - return secretVolumeCertificateProviders.findOrCreate(configSource, name); - } - - private final TlsCertificateSecretProviderMap secretVolumeCertificateProviders = - new TlsCertificateSecretProviderMap(); -} diff --git a/xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java b/xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java deleted file mode 100644 index d9a8d97af51..00000000000 --- a/xds/src/main/java/io/grpc/xds/sds/SecretProviderMap.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.envoyproxy.envoy.api.v2.core.ConfigSource; - -import java.util.HashMap; -import java.util.Map; - -/** - * SecretProviderMap used by SecretManager to maintain certificateProviders. - * - * @param Type of secret stored in this Map - */ -abstract class SecretProviderMap { - - private final Map> providers; - - protected SecretProviderMap() { - providers = new HashMap<>(); - } - - /** - * Finds an existing SecretProvider or creates it if it doesn't exist. - * - * @param configSource source part of the SdsSecretConfig - * @param name name of the SdsSecretConfig - * @return SecrerProvider - */ - final synchronized SecretProvider findOrCreate( - ConfigSource configSource, String name) { - checkNotNull(configSource, "configSource"); - checkNotNull(name, "name"); - - String mapKey = "" + configSource.hashCode() + "." + name; - SecretProvider provider = providers.get(mapKey); - if (provider == null) { - provider = create(configSource, name); - providers.put(mapKey, provider); - } - return provider; - } - - abstract SecretProvider create(ConfigSource configSource, String name); -} diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java deleted file mode 100644 index 25d8959bc0a..00000000000 --- a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretProviderMap.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.base.Preconditions.checkNotNull; - -import io.envoyproxy.envoy.api.v2.core.ConfigSource; - -final class TlsCertificateSecretProviderMap extends SecretProviderMap { - - @Override - SecretProvider create(ConfigSource configSource, String name) { - checkNotNull(configSource, "configSource"); - checkNotNull(name, "name"); - // for now we support only path/volume based secret provider - if (configSource.getConfigSourceSpecifierCase() - != ConfigSource.ConfigSourceSpecifierCase.PATH) { - throw new UnsupportedOperationException("Only file based secret supported"); - } - return new TlsCertificateSecretVolumeSecretProvider(configSource.getPath(), name); - } -} diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java deleted file mode 100644 index 27f266d5ad0..00000000000 --- a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProvider.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.VisibleForTesting; -import com.google.protobuf.ByteString; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * Implementation of a file based secret provider. - */ -final class TlsCertificateSecretVolumeSecretProvider - implements SecretProvider { - - public static final String PEM = ".pem"; - public static final String CRT = ".crt"; - private static final Logger logger = Logger - .getLogger(TlsCertificateSecretVolumeSecretProvider.class.getName()); - private final String path; - - // for now mark it unused - @SuppressWarnings("unused") - private final String name; - - TlsCertificateSecretVolumeSecretProvider(String path, String name) { - this.path = checkNotNull(path, "path"); - this.name = checkNotNull(name, "name"); - } - - @Override - public void addCallback(final Callback callback, Executor executor) { - checkNotNull(callback, "callback"); - checkNotNull(executor, "executor"); - executor.execute(new Runnable() { - @Override - public void run() { - // as per the contract of this provider we will get the current on-disk - // contents of the files - try { - TlsCertificateStore tlsCert = get(); - callback.updateSecret(tlsCert); - } catch (ExecutionException e) { - logger.log( - Level.SEVERE, - "RuntimeException from get()", - e); - } - } - }); - } - - /** - * Gets the current contents of the private key and cert file. Assume the key has - * .pem extension and cert has .crt extension - * (needs to match mounted secrets). - */ - @VisibleForTesting - TlsCertificateStore get() throws ExecutionException { - try { - final FileInputStream pemStream = new FileInputStream(path + PEM); - final FileInputStream crtStream = new FileInputStream(path + CRT); - return new TlsCertificateStore(ByteString.readFrom(pemStream), - ByteString.readFrom(crtStream)); - } catch (IOException e) { - throw new ExecutionException(e); - } - } -} diff --git a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java b/xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java deleted file mode 100644 index 3cf4ef6f852..00000000000 --- a/xds/src/main/java/io/grpc/xds/sds/TlsCertificateStore.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.protobuf.ByteString; -import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; -import io.envoyproxy.envoy.api.v2.core.DataSource; -import io.grpc.Internal; - -/** - * TlsCertificate's PrivateKey and Certificate are extracted into ByteString's. - * Used by the gRPC SSLContext/Protocol Negotiator and is internal. - * See {@link SecretManager} for a note on lifecycle management. - */ -@Internal -public final class TlsCertificateStore { - - private final ByteString privateKey; - private final ByteString certChain; - - private static ByteString getByteStringFromDataSource(DataSource dataSource) { - checkNotNull(dataSource); - ByteString dataSourceByteString = null; - if (dataSource.getSpecifierCase() == DataSource.SpecifierCase.INLINE_BYTES) { - dataSourceByteString = dataSource.getInlineBytes(); - } else if (dataSource.getSpecifierCase() == DataSource.SpecifierCase.INLINE_STRING) { - dataSourceByteString = dataSource.getInlineStringBytes(); - } else { - throw new UnsupportedOperationException( - "dataSource of type " + dataSource.getSpecifierCase() + " not supported"); - } - return dataSourceByteString; - } - - /** - * Creates the Store out of the TlsCertificate object of xDS. - * - * @param tlsCertificate TlsCertificate Object of xDS - */ - public TlsCertificateStore(TlsCertificate tlsCertificate) { - this( - getByteStringFromDataSource(checkNotNull(tlsCertificate).getPrivateKey()), - getByteStringFromDataSource(tlsCertificate.getCertificateChain())); - } - - /** - * Creates the Store out of 2 streams for the 2 certs on disk. - * - * @param privateKeySteam stream representing private key on disk - * @param certChain stream representing cert on disk - */ - public TlsCertificateStore(ByteString privateKeySteam, ByteString certChain) { - checkNotNull(privateKeySteam); - checkNotNull(certChain); - this.privateKey = privateKeySteam; - this.certChain = certChain; - } - - /** - * getter for private key stream. - * - * @return inputStream representing private key - */ - public ByteString getPrivateKey() { - return privateKey; - } - - /** - * getter for cert key stream. - * - * @return inputStream representing cert - */ - public ByteString getCertChain() { - return certChain; - } -} diff --git a/xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java b/xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java deleted file mode 100644 index d0b8ff91e43..00000000000 --- a/xds/src/test/java/io/grpc/xds/sds/SecretManagerTest.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.truth.Truth.assertThat; - -import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; -import io.envoyproxy.envoy.api.v2.core.ConfigSource; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Unit tests for {@link SecretManager}. - */ -@RunWith(JUnit4.class) -public class SecretManagerTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Test - public void createTest() throws IOException, ExecutionException, InterruptedException { - ConfigSource configSource = TlsCertificateSecretProviderMapTest - .createFileAndConfigSource(temporaryFolder); - - SecretManager secretManager = new SecretManager(); - SecretProvider provider = secretManager - .findOrCreateTlsCertificateProvider(configSource, "test"); - assertThat(provider).isNotNull(); - TlsCertificateStore tlsCertificateStore = - TlsCertificateSecretProviderMapTest.getValueThruCallback(provider); - assertThat(tlsCertificateStore).isNotNull(); - TlsCertificateStoreTest - .verifyKeyAndCertsWithStrings(tlsCertificateStore, "pemContents", "crtContents"); - } - - @Test - @SuppressWarnings("unused") - public void nonFilePathConfigSource() { - ConfigSource configSource = - ConfigSource.newBuilder() - .setApiConfigSource(ApiConfigSource.newBuilder().build()) - .build(); - - //thrown.expect(UnsupportedOperationException.class); - SecretManager secretManager = new SecretManager(); - try { - SecretProvider provider = secretManager - .findOrCreateTlsCertificateProvider(configSource, "test"); - Assert.fail("no exception thrown"); - } catch (UnsupportedOperationException expected) { - assertThat(expected).hasMessageThat() - .contains("Only file based secret supported"); - } - } - -} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java deleted file mode 100644 index 297b1b022bd..00000000000 --- a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretProviderMapTest.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.common.util.concurrent.MoreExecutors; -import io.envoyproxy.envoy.api.v2.core.ApiConfigSource; -import io.envoyproxy.envoy.api.v2.core.ConfigSource; -import java.io.File; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Unit tests for {@link TlsCertificateSecretProviderMap}. - */ -@RunWith(JUnit4.class) -public class TlsCertificateSecretProviderMapTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - /** - * Utility function for creation of test files in a temp folder. - * Used in other classes - * - * @param temporaryFolder temporary folder to use - * @return a config source representing the file based secret - * @throws IOException represents IO exception - */ - static ConfigSource createFileAndConfigSource(TemporaryFolder temporaryFolder) - throws IOException { - File filePath = TlsCertificateSecretVolumeSecretProviderTest - .createTestCertFiles(temporaryFolder); - - return ConfigSource.newBuilder() - .setPath(filePath.getPath()) - .build(); - } - - /** - * Helper method to get the value thru directExecutore callback. Used by other classes. - */ - static TlsCertificateStore getValueThruCallback(SecretProvider provider) { - SslContextSecretVolumeSecretProviderTest.TestCallback testCallback - = new SslContextSecretVolumeSecretProviderTest.TestCallback<>(); - provider.addCallback(testCallback, MoreExecutors.directExecutor()); - return testCallback.updatedSecret; - } - - @Test - public void createTest() throws IOException, ExecutionException, InterruptedException { - ConfigSource configSource = createFileAndConfigSource(temporaryFolder); - TlsCertificateSecretProviderMap map = new TlsCertificateSecretProviderMap(); - SecretProvider provider = map.findOrCreate(configSource, "test"); - assertThat(provider).isNotNull(); - TlsCertificateStore tlsCertificateStore = getValueThruCallback(provider); - assertThat(tlsCertificateStore).isNotNull(); - TlsCertificateStoreTest - .verifyKeyAndCertsWithStrings(tlsCertificateStore, "pemContents", "crtContents"); - } - - @Test - public void nonFilePathConfigSource() { - ConfigSource configSource = - ConfigSource.newBuilder() - .setApiConfigSource(ApiConfigSource.newBuilder().build()) - .build(); - - TlsCertificateSecretProviderMap map = new TlsCertificateSecretProviderMap(); - try { - SecretProvider unused = map.findOrCreate(configSource, "test"); - Assert.fail("no exception thrown"); - } catch (UnsupportedOperationException expected) { - assertThat(expected).hasMessageThat() - .contains("Only file based secret supported"); - } - } - -} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java deleted file mode 100644 index cc202f4a5b9..00000000000 --- a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateSecretVolumeSecretProviderTest.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.truth.Truth.assertThat; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.util.concurrent.MoreExecutors; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.Writer; -import java.nio.file.Files; -import java.util.concurrent.ExecutionException; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Unit tests for {@link TlsCertificateSecretVolumeSecretProvider}. - */ -@RunWith(JUnit4.class) -public class TlsCertificateSecretVolumeSecretProviderTest { - - @Rule - public TemporaryFolder temporaryFolder = new TemporaryFolder(); - - /** - * Utility function for creation of test files in a temp folder. - * - * @param temporaryFolder temporary folder to use - * @return a config source representing the file based secret - * @throws IOException represents an IO exception - */ - static File createTestCertFiles(TemporaryFolder temporaryFolder) throws IOException { - createATestCertFile(temporaryFolder, "mycert.pem", "pemContents"); - createATestCertFile(temporaryFolder, "mycert.crt", "crtContents"); - - return new File(temporaryFolder.getRoot(), "mycert"); - } - - private static void createATestCertFile( - TemporaryFolder temporaryFolder, - String s, - String pemContents) throws IOException { - File pem = temporaryFolder.newFile(s); - Writer pemFile = Files.newBufferedWriter(pem.toPath(), UTF_8); - pemFile.write(pemContents); - pemFile.close(); - } - - @Test - public void readBothFiles() throws IOException, ExecutionException, InterruptedException { - File filePath = createTestCertFiles(temporaryFolder); - TlsCertificateSecretVolumeSecretProvider provider = - new TlsCertificateSecretVolumeSecretProvider(filePath.getPath(), "test"); - - TlsCertificateStore tlsCertificateStore = provider.get(); - assertThat(tlsCertificateStore).isNotNull(); - TlsCertificateStoreTest - .verifyKeyAndCertsWithStrings(tlsCertificateStore, "pemContents", "crtContents"); - } - - private boolean listenerRun; - - @Test - public void verifyCallbackExecuted() - throws IOException, ExecutionException, InterruptedException { - // with a valid file we should get a callback - File filePath = createTestCertFiles(temporaryFolder); - TlsCertificateSecretVolumeSecretProvider provider = - new TlsCertificateSecretVolumeSecretProvider(filePath.getPath(), "test"); - - listenerRun = false; - provider.addCallback(new SecretProvider.Callback() { - - @Override - public void updateSecret(TlsCertificateStore secret) { - listenerRun = true; - } - - @Override - public void onException(Throwable throwable) { - - } - }, MoreExecutors.directExecutor()); - assertThat(listenerRun).isTrue(); - } - - @Test - public void readMissingFile() throws IOException, ExecutionException, InterruptedException { - createATestCertFile(temporaryFolder, "mycert.pem", "pemContents"); - - // no crt file - File filePath = new File(temporaryFolder.getRoot(), "mycert"); - TlsCertificateSecretVolumeSecretProvider provider = - new TlsCertificateSecretVolumeSecretProvider(filePath.getPath(), "test"); - - try { - provider.get(); - Assert.fail("no exception thrown"); - } catch (ExecutionException expected) { - assertThat(expected.getCause()).isInstanceOf(FileNotFoundException.class); - } - } - - @Test - public void verifyCallbackNotExecuted() - throws IOException, ExecutionException, InterruptedException { - // with an invalid file we should NOT get a callback - - TlsCertificateSecretVolumeSecretProvider provider = - new TlsCertificateSecretVolumeSecretProvider("/a/b/test", "test"); - - listenerRun = false; - provider.addCallback(new SecretProvider.Callback() { - - @Override - public void updateSecret(TlsCertificateStore secret) { - listenerRun = true; - } - - @Override - public void onException(Throwable throwable) { - - } - }, MoreExecutors.directExecutor()); - assertThat(listenerRun).isFalse(); - } -} diff --git a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java b/xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java deleted file mode 100644 index c34e030c540..00000000000 --- a/xds/src/test/java/io/grpc/xds/sds/TlsCertificateStoreTest.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.xds.sds; - -import static com.google.common.truth.Truth.assertThat; - -import com.google.protobuf.ByteString; -import io.envoyproxy.envoy.api.v2.auth.TlsCertificate; -import io.envoyproxy.envoy.api.v2.core.DataSource; -import java.io.IOException; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** - * Unit tests for {@link TlsCertificateStore}. - */ -@RunWith(JUnit4.class) -public class TlsCertificateStoreTest { - - static void verifyKeyAndCertsWithStrings(TlsCertificateStore tlsCertificateStore, String s1, - String s2) throws IOException { - verifyKeyAndCertsWithStrings(tlsCertificateStore.getPrivateKey(), s1); - verifyKeyAndCertsWithStrings(tlsCertificateStore.getCertChain(), s2); - } - - private static void verifyKeyAndCertsWithStrings(ByteString byteString, String s) - throws IOException { - assertThat(byteString).isNotNull(); - assertThat(byteString.toStringUtf8()).isEqualTo(s); - } - - @Test - public void convertFromTlsCertificateUsingString() throws IOException { - DataSource privateKey = - DataSource.newBuilder() - .setInlineString("test-privateKey") - .build(); - DataSource certChain = - DataSource.newBuilder() - .setInlineString("test-certChain") - .build(); - - TlsCertificate tlsCertificate = - TlsCertificate.newBuilder() - .setPrivateKey(privateKey) - .setCertificateChain(certChain) - .build(); - - TlsCertificateStore tlsCertificateStore = new TlsCertificateStore(tlsCertificate); - - verifyKeyAndCertsWithStrings(tlsCertificateStore, "test-privateKey", "test-certChain"); - } - - @Test - public void convertFromTlsCertificateUsingBytes() throws IOException { - byte[] privateKeyBytes = {1, 2, 3, 4}; - byte[] certChainBytes = {4, 3, 2, 1}; - - DataSource privateKey = - DataSource.newBuilder() - .setInlineBytes(ByteString.copyFrom(privateKeyBytes)) - .build(); - DataSource certChain = - DataSource.newBuilder() - .setInlineBytes(ByteString.copyFrom(certChainBytes)) - .build(); - - TlsCertificate tlsCertificate = - TlsCertificate.newBuilder() - .setPrivateKey(privateKey) - .setCertificateChain(certChain) - .build(); - - TlsCertificateStore tlsCertificateStore = new TlsCertificateStore(tlsCertificate); - - ByteString privateKeyByteString = tlsCertificateStore.getPrivateKey(); - assertThat(privateKeyByteString).isNotNull(); - assertThat(privateKeyByteString.toByteArray()).isEqualTo(privateKeyBytes); - - ByteString certChainByteString = tlsCertificateStore.getCertChain(); - assertThat(certChainByteString).isNotNull(); - assertThat(certChainByteString.toByteArray()).isEqualTo(certChainBytes); - } - - @Test - public void privateKeyNotSet() { - DataSource certChain = - DataSource.newBuilder() - .setInlineString("test-certChain") - .build(); - TlsCertificate tlsCertificate = - TlsCertificate.newBuilder() - .setCertificateChain(certChain) - .build(); - - try { - new TlsCertificateStore(tlsCertificate); - Assert.fail("no exception thrown"); - } catch (UnsupportedOperationException expected) { - assertThat(expected).hasMessageThat() - .contains("dataSource of type SPECIFIER_NOT_SET not supported"); - } - } - - @Test - public void certChainNotSet() { - DataSource privateKey = - DataSource.newBuilder() - .setInlineString("test-privateKey") - .build(); - TlsCertificate tlsCertificate = - TlsCertificate.newBuilder() - .setPrivateKey(privateKey) - .build(); - try { - new TlsCertificateStore(tlsCertificate); - Assert.fail("no exception thrown"); - } catch (UnsupportedOperationException expected) { - assertThat(expected).hasMessageThat() - .contains("dataSource of type SPECIFIER_NOT_SET not supported"); - } - } - -} From 4503a233f4dcc04df49ee80f436bc77de47050ec Mon Sep 17 00:00:00 2001 From: Carl Mastrangelo Date: Wed, 25 Sep 2019 19:29:42 -0700 Subject: [PATCH 117/131] api: stabilize safe and idempotent methods in MethodDescriptor --- api/src/main/java/io/grpc/MethodDescriptor.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/api/src/main/java/io/grpc/MethodDescriptor.java b/api/src/main/java/io/grpc/MethodDescriptor.java index 2c55af4905f..e9f8dd063c3 100644 --- a/api/src/main/java/io/grpc/MethodDescriptor.java +++ b/api/src/main/java/io/grpc/MethodDescriptor.java @@ -350,7 +350,6 @@ public Marshaller getResponseMarshaller() { * * @since 1.0.0 */ - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") public boolean isIdempotent() { return idempotent; } @@ -362,7 +361,6 @@ public boolean isIdempotent() { * * @since 1.1.0 */ - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") public boolean isSafe() { return safe; } @@ -539,7 +537,6 @@ public Builder setSchemaDescriptor(@Nullable Object schemaDescripto * * @since 1.1.0 */ - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") public Builder setIdempotent(boolean idempotent) { this.idempotent = idempotent; if (!idempotent) { @@ -555,7 +552,6 @@ public Builder setIdempotent(boolean idempotent) { * * @since 1.1.0 */ - @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1775") public Builder setSafe(boolean safe) { this.safe = safe; if (safe) { From f2d0f87d2ec5550ab4c27d534b2cf2b9dc335823 Mon Sep 17 00:00:00 2001 From: Carl Mastrangelo Date: Wed, 25 Sep 2019 20:10:06 -0700 Subject: [PATCH 118/131] compiler: set safe and idempotent bits on method descriptors --- .../src/java_plugin/cpp/java_generator.cpp | 17 +- compiler/src/test/golden/TestService.java.txt | 182 +++++++++++++++++- .../proto/grpc/testing/compiler/test.proto | 12 +- .../src/testLite/golden/TestService.java.txt | 180 ++++++++++++++++- .../io/grpc/okhttp/OkHttpChannelBuilder.java | 2 +- 5 files changed, 382 insertions(+), 11 deletions(-) diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp index 34cdb734dfd..5232f11fa53 100644 --- a/compiler/src/java_plugin/cpp/java_generator.cpp +++ b/compiler/src/java_plugin/cpp/java_generator.cpp @@ -426,7 +426,22 @@ static void PrintMethodFields( " $service_class_name$.$method_new_field_name$ = $method_new_field_name$ =\n" " $MethodDescriptor$.<$input_type$, $output_type$>newBuilder()\n" " .setType($MethodType$.$method_type$)\n" - " .setFullMethodName(generateFullMethodName(SERVICE_NAME, \"$method_name$\"))\n" + " .setFullMethodName(generateFullMethodName(SERVICE_NAME, \"$method_name$\"))\n"); + + bool safe = method->options().idempotency_level() + == google::protobuf::MethodOptions_IdempotencyLevel_NO_SIDE_EFFECTS; + if (safe) { + p->Print(*vars, " .setSafe(true)\n"); + } else { + bool idempotent = method->options().idempotency_level() + == google::protobuf::MethodOptions_IdempotencyLevel_IDEMPOTENT; + if (idempotent) { + p->Print(*vars, " .setIdempotent(true)\n"); + } + } + + p->Print( + *vars, " .setSampledToLocalTracing(true)\n" " .setRequestMarshaller($ProtoUtils$.marshaller(\n" " $input_type$.getDefaultInstance()))\n" diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index d3e5e984649..5268ee46b5d 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -216,6 +216,70 @@ public final class TestServiceGrpc { return getImportMethod; } + private static volatile io.grpc.MethodDescriptor getSafeCallMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SafeCall", + requestType = io.grpc.testing.compiler.Test.SimpleRequest.class, + responseType = io.grpc.testing.compiler.Test.SimpleResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getSafeCallMethod() { + io.grpc.MethodDescriptor getSafeCallMethod; + if ((getSafeCallMethod = TestServiceGrpc.getSafeCallMethod) == null) { + synchronized (TestServiceGrpc.class) { + if ((getSafeCallMethod = TestServiceGrpc.getSafeCallMethod) == null) { + TestServiceGrpc.getSafeCallMethod = getSafeCallMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SafeCall")) + .setSafe(true) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleResponse.getDefaultInstance())) + .setSchemaDescriptor(new TestServiceMethodDescriptorSupplier("SafeCall")) + .build(); + } + } + } + return getSafeCallMethod; + } + + private static volatile io.grpc.MethodDescriptor getIdempotentCallMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "IdempotentCall", + requestType = io.grpc.testing.compiler.Test.SimpleRequest.class, + responseType = io.grpc.testing.compiler.Test.SimpleResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getIdempotentCallMethod() { + io.grpc.MethodDescriptor getIdempotentCallMethod; + if ((getIdempotentCallMethod = TestServiceGrpc.getIdempotentCallMethod) == null) { + synchronized (TestServiceGrpc.class) { + if ((getIdempotentCallMethod = TestServiceGrpc.getIdempotentCallMethod) == null) { + TestServiceGrpc.getIdempotentCallMethod = getIdempotentCallMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "IdempotentCall")) + .setIdempotent(true) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.ProtoUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleResponse.getDefaultInstance())) + .setSchemaDescriptor(new TestServiceMethodDescriptorSupplier("IdempotentCall")) + .build(); + } + } + } + return getIdempotentCallMethod; + } + /** * Creates a new async stub that supports all call types for the service */ @@ -336,6 +400,26 @@ public final class TestServiceGrpc { return asyncUnimplementedStreamingCall(getImportMethod(), responseObserver); } + /** + *

    +     * A unary call that is Safe.
    +     * 
    + */ + public void safeCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getSafeCallMethod(), responseObserver); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public void idempotentCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getIdempotentCallMethod(), responseObserver); + } + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) .addMethod( @@ -380,6 +464,20 @@ public final class TestServiceGrpc { io.grpc.testing.compiler.Test.StreamingInputCallRequest, io.grpc.testing.compiler.Test.StreamingInputCallResponse>( this, METHODID_IMPORT))) + .addMethod( + getSafeCallMethod(), + asyncUnaryCall( + new MethodHandlers< + io.grpc.testing.compiler.Test.SimpleRequest, + io.grpc.testing.compiler.Test.SimpleResponse>( + this, METHODID_SAFE_CALL))) + .addMethod( + getIdempotentCallMethod(), + asyncUnaryCall( + new MethodHandlers< + io.grpc.testing.compiler.Test.SimpleRequest, + io.grpc.testing.compiler.Test.SimpleResponse>( + this, METHODID_IDEMPOTENT_CALL))) .build(); } } @@ -475,6 +573,28 @@ public final class TestServiceGrpc { return asyncBidiStreamingCall( getChannel().newCall(getImportMethod(), getCallOptions()), responseObserver); } + + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public void safeCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getSafeCallMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public void idempotentCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getIdempotentCallMethod(), getCallOptions()), request, responseObserver); + } } /** @@ -516,6 +636,26 @@ public final class TestServiceGrpc { return blockingServerStreamingCall( getChannel(), getStreamingOutputCallMethod(), getCallOptions(), request); } + + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public io.grpc.testing.compiler.Test.SimpleResponse safeCall(io.grpc.testing.compiler.Test.SimpleRequest request) { + return blockingUnaryCall( + getChannel(), getSafeCallMethod(), getCallOptions(), request); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public io.grpc.testing.compiler.Test.SimpleResponse idempotentCall(io.grpc.testing.compiler.Test.SimpleRequest request) { + return blockingUnaryCall( + getChannel(), getIdempotentCallMethod(), getCallOptions(), request); + } } /** @@ -546,14 +686,38 @@ public final class TestServiceGrpc { return futureUnaryCall( getChannel().newCall(getUnaryCallMethod(), getCallOptions()), request); } + + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public com.google.common.util.concurrent.ListenableFuture safeCall( + io.grpc.testing.compiler.Test.SimpleRequest request) { + return futureUnaryCall( + getChannel().newCall(getSafeCallMethod(), getCallOptions()), request); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public com.google.common.util.concurrent.ListenableFuture idempotentCall( + io.grpc.testing.compiler.Test.SimpleRequest request) { + return futureUnaryCall( + getChannel().newCall(getIdempotentCallMethod(), getCallOptions()), request); + } } private static final int METHODID_UNARY_CALL = 0; private static final int METHODID_STREAMING_OUTPUT_CALL = 1; - private static final int METHODID_STREAMING_INPUT_CALL = 2; - private static final int METHODID_FULL_BIDI_CALL = 3; - private static final int METHODID_HALF_BIDI_CALL = 4; - private static final int METHODID_IMPORT = 5; + private static final int METHODID_SAFE_CALL = 2; + private static final int METHODID_IDEMPOTENT_CALL = 3; + private static final int METHODID_STREAMING_INPUT_CALL = 4; + private static final int METHODID_FULL_BIDI_CALL = 5; + private static final int METHODID_HALF_BIDI_CALL = 6; + private static final int METHODID_IMPORT = 7; private static final class MethodHandlers implements io.grpc.stub.ServerCalls.UnaryMethod, @@ -580,6 +744,14 @@ public final class TestServiceGrpc { serviceImpl.streamingOutputCall((io.grpc.testing.compiler.Test.StreamingOutputCallRequest) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_SAFE_CALL: + serviceImpl.safeCall((io.grpc.testing.compiler.Test.SimpleRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_IDEMPOTENT_CALL: + serviceImpl.idempotentCall((io.grpc.testing.compiler.Test.SimpleRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; default: throw new AssertionError(); } @@ -659,6 +831,8 @@ public final class TestServiceGrpc { .addMethod(getFullBidiCallMethod()) .addMethod(getHalfBidiCallMethod()) .addMethod(getImportMethod()) + .addMethod(getSafeCallMethod()) + .addMethod(getIdempotentCallMethod()) .build(); } } diff --git a/compiler/src/test/proto/grpc/testing/compiler/test.proto b/compiler/src/test/proto/grpc/testing/compiler/test.proto index 62cf6c853a8..c1cb5572166 100644 --- a/compiler/src/test/proto/grpc/testing/compiler/test.proto +++ b/compiler/src/test/proto/grpc/testing/compiler/test.proto @@ -70,6 +70,16 @@ service TestService { // An RPC method whose Java name collides with a keyword, and whose generated // method should have a '_' appended. rpc Import(stream StreamingInputCallRequest) returns (stream StreamingInputCallResponse); + + // A unary call that is Safe. + rpc SafeCall(SimpleRequest) returns (SimpleResponse) { + option idempotency_level = NO_SIDE_EFFECTS; + } + + // A unary call that is Idempotent. + rpc IdempotentCall(SimpleRequest) returns (SimpleResponse) { + option idempotency_level = IDEMPOTENT; + } } // Test service that has been deprecated and should generate with Java's @Deprecated annotation @@ -80,4 +90,4 @@ service TestDeprecatedService { rpc DeprecatedMethod(SimpleRequest) returns (SimpleResponse) { option deprecated = true; } -} \ No newline at end of file +} diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt index e79a843236f..c0d17510db6 100644 --- a/compiler/src/testLite/golden/TestService.java.txt +++ b/compiler/src/testLite/golden/TestService.java.txt @@ -210,6 +210,68 @@ public final class TestServiceGrpc { return getImportMethod; } + private static volatile io.grpc.MethodDescriptor getSafeCallMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "SafeCall", + requestType = io.grpc.testing.compiler.Test.SimpleRequest.class, + responseType = io.grpc.testing.compiler.Test.SimpleResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getSafeCallMethod() { + io.grpc.MethodDescriptor getSafeCallMethod; + if ((getSafeCallMethod = TestServiceGrpc.getSafeCallMethod) == null) { + synchronized (TestServiceGrpc.class) { + if ((getSafeCallMethod = TestServiceGrpc.getSafeCallMethod) == null) { + TestServiceGrpc.getSafeCallMethod = getSafeCallMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "SafeCall")) + .setSafe(true) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.lite.ProtoLiteUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.lite.ProtoLiteUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleResponse.getDefaultInstance())) + .build(); + } + } + } + return getSafeCallMethod; + } + + private static volatile io.grpc.MethodDescriptor getIdempotentCallMethod; + + @io.grpc.stub.annotations.RpcMethod( + fullMethodName = SERVICE_NAME + '/' + "IdempotentCall", + requestType = io.grpc.testing.compiler.Test.SimpleRequest.class, + responseType = io.grpc.testing.compiler.Test.SimpleResponse.class, + methodType = io.grpc.MethodDescriptor.MethodType.UNARY) + public static io.grpc.MethodDescriptor getIdempotentCallMethod() { + io.grpc.MethodDescriptor getIdempotentCallMethod; + if ((getIdempotentCallMethod = TestServiceGrpc.getIdempotentCallMethod) == null) { + synchronized (TestServiceGrpc.class) { + if ((getIdempotentCallMethod = TestServiceGrpc.getIdempotentCallMethod) == null) { + TestServiceGrpc.getIdempotentCallMethod = getIdempotentCallMethod = + io.grpc.MethodDescriptor.newBuilder() + .setType(io.grpc.MethodDescriptor.MethodType.UNARY) + .setFullMethodName(generateFullMethodName(SERVICE_NAME, "IdempotentCall")) + .setIdempotent(true) + .setSampledToLocalTracing(true) + .setRequestMarshaller(io.grpc.protobuf.lite.ProtoLiteUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleRequest.getDefaultInstance())) + .setResponseMarshaller(io.grpc.protobuf.lite.ProtoLiteUtils.marshaller( + io.grpc.testing.compiler.Test.SimpleResponse.getDefaultInstance())) + .build(); + } + } + } + return getIdempotentCallMethod; + } + /** * Creates a new async stub that supports all call types for the service */ @@ -330,6 +392,26 @@ public final class TestServiceGrpc { return asyncUnimplementedStreamingCall(getImportMethod(), responseObserver); } + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public void safeCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getSafeCallMethod(), responseObserver); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public void idempotentCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnimplementedUnaryCall(getIdempotentCallMethod(), responseObserver); + } + @java.lang.Override public final io.grpc.ServerServiceDefinition bindService() { return io.grpc.ServerServiceDefinition.builder(getServiceDescriptor()) .addMethod( @@ -374,6 +456,20 @@ public final class TestServiceGrpc { io.grpc.testing.compiler.Test.StreamingInputCallRequest, io.grpc.testing.compiler.Test.StreamingInputCallResponse>( this, METHODID_IMPORT))) + .addMethod( + getSafeCallMethod(), + asyncUnaryCall( + new MethodHandlers< + io.grpc.testing.compiler.Test.SimpleRequest, + io.grpc.testing.compiler.Test.SimpleResponse>( + this, METHODID_SAFE_CALL))) + .addMethod( + getIdempotentCallMethod(), + asyncUnaryCall( + new MethodHandlers< + io.grpc.testing.compiler.Test.SimpleRequest, + io.grpc.testing.compiler.Test.SimpleResponse>( + this, METHODID_IDEMPOTENT_CALL))) .build(); } } @@ -469,6 +565,28 @@ public final class TestServiceGrpc { return asyncBidiStreamingCall( getChannel().newCall(getImportMethod(), getCallOptions()), responseObserver); } + + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public void safeCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getSafeCallMethod(), getCallOptions()), request, responseObserver); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public void idempotentCall(io.grpc.testing.compiler.Test.SimpleRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + getChannel().newCall(getIdempotentCallMethod(), getCallOptions()), request, responseObserver); + } } /** @@ -510,6 +628,26 @@ public final class TestServiceGrpc { return blockingServerStreamingCall( getChannel(), getStreamingOutputCallMethod(), getCallOptions(), request); } + + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public io.grpc.testing.compiler.Test.SimpleResponse safeCall(io.grpc.testing.compiler.Test.SimpleRequest request) { + return blockingUnaryCall( + getChannel(), getSafeCallMethod(), getCallOptions(), request); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public io.grpc.testing.compiler.Test.SimpleResponse idempotentCall(io.grpc.testing.compiler.Test.SimpleRequest request) { + return blockingUnaryCall( + getChannel(), getIdempotentCallMethod(), getCallOptions(), request); + } } /** @@ -540,14 +678,38 @@ public final class TestServiceGrpc { return futureUnaryCall( getChannel().newCall(getUnaryCallMethod(), getCallOptions()), request); } + + /** + *
    +     * A unary call that is Safe.
    +     * 
    + */ + public com.google.common.util.concurrent.ListenableFuture safeCall( + io.grpc.testing.compiler.Test.SimpleRequest request) { + return futureUnaryCall( + getChannel().newCall(getSafeCallMethod(), getCallOptions()), request); + } + + /** + *
    +     * A unary call that is Idempotent.
    +     * 
    + */ + public com.google.common.util.concurrent.ListenableFuture idempotentCall( + io.grpc.testing.compiler.Test.SimpleRequest request) { + return futureUnaryCall( + getChannel().newCall(getIdempotentCallMethod(), getCallOptions()), request); + } } private static final int METHODID_UNARY_CALL = 0; private static final int METHODID_STREAMING_OUTPUT_CALL = 1; - private static final int METHODID_STREAMING_INPUT_CALL = 2; - private static final int METHODID_FULL_BIDI_CALL = 3; - private static final int METHODID_HALF_BIDI_CALL = 4; - private static final int METHODID_IMPORT = 5; + private static final int METHODID_SAFE_CALL = 2; + private static final int METHODID_IDEMPOTENT_CALL = 3; + private static final int METHODID_STREAMING_INPUT_CALL = 4; + private static final int METHODID_FULL_BIDI_CALL = 5; + private static final int METHODID_HALF_BIDI_CALL = 6; + private static final int METHODID_IMPORT = 7; private static final class MethodHandlers implements io.grpc.stub.ServerCalls.UnaryMethod, @@ -574,6 +736,14 @@ public final class TestServiceGrpc { serviceImpl.streamingOutputCall((io.grpc.testing.compiler.Test.StreamingOutputCallRequest) request, (io.grpc.stub.StreamObserver) responseObserver); break; + case METHODID_SAFE_CALL: + serviceImpl.safeCall((io.grpc.testing.compiler.Test.SimpleRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; + case METHODID_IDEMPOTENT_CALL: + serviceImpl.idempotentCall((io.grpc.testing.compiler.Test.SimpleRequest) request, + (io.grpc.stub.StreamObserver) responseObserver); + break; default: throw new AssertionError(); } @@ -617,6 +787,8 @@ public final class TestServiceGrpc { .addMethod(getFullBidiCallMethod()) .addMethod(getHalfBidiCallMethod()) .addMethod(getImportMethod()) + .addMethod(getSafeCallMethod()) + .addMethod(getIdempotentCallMethod()) .build(); } } diff --git a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java index b8071d9cf62..690462ba6ae 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java +++ b/okhttp/src/main/java/io/grpc/okhttp/OkHttpChannelBuilder.java @@ -133,7 +133,7 @@ public static OkHttpChannelBuilder forTarget(String target) { * If true, indicates that the transport may use the GET method for RPCs, and may include the * request body in the query params. */ - private final boolean useGetForSafeMethods = true; + private final boolean useGetForSafeMethods = false; protected OkHttpChannelBuilder(String host, int port) { this(GrpcUtil.authorityFromHostAndPort(host, port)); From 2eb3f8c34e58b2371cafa0728ae1ba1feec121da Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Tue, 22 Oct 2019 13:27:30 -0700 Subject: [PATCH 119/131] stub,compiler: Rollback Abstract{Future,Blocking,Async}Stub (#6317) rollback of #6304 & #6196 --- .../alts/internal/HandshakerServiceGrpc.java | 69 ++++++------- .../proto/BenchmarkServiceGrpc.java | 69 ++++++------- .../proto/ReportQpsScenarioServiceGrpc.java | 69 ++++++------- .../benchmarks/proto/WorkerServiceGrpc.java | 69 ++++++------- .../src/java_plugin/cpp/java_generator.cpp | 76 ++++----------- .../golden/TestDeprecatedService.java.txt | 69 ++++++------- compiler/src/test/golden/TestService.java.txt | 69 ++++++------- .../golden/TestDeprecatedService.java.txt | 69 ++++++------- .../src/testLite/golden/TestService.java.txt | 69 ++++++------- .../grpc/io/grpc/lb/v1/LoadBalancerGrpc.java | 69 ++++++------- .../integration/MetricsServiceGrpc.java | 69 ++++++------- .../integration/ReconnectServiceGrpc.java | 69 ++++++------- .../testing/integration/TestServiceGrpc.java | 69 ++++++------- .../integration/UnimplementedServiceGrpc.java | 69 ++++++------- .../io/grpc/channelz/v1/ChannelzGrpc.java | 69 ++++++------- .../grpc/io/grpc/health/v1/HealthGrpc.java | 69 ++++++------- .../v1alpha/ServerReflectionGrpc.java | 69 ++++++------- .../testing/AnotherDynamicServiceGrpc.java | 69 ++++++------- .../testing/DynamicServiceGrpc.java | 69 ++++++------- .../testing/ReflectableServiceGrpc.java | 69 ++++++------- .../java/io/grpc/stub/AbstractAsyncStub.java | 69 ------------- .../io/grpc/stub/AbstractBlockingStub.java | 70 ------------- .../java/io/grpc/stub/AbstractFutureStub.java | 70 ------------- .../main/java/io/grpc/stub/AbstractStub.java | 34 ------- .../main/java/io/grpc/stub/ClientCalls.java | 10 -- .../io/grpc/stub/InternalClientCalls.java | 61 ------------ .../io/grpc/stub/AbstractAsyncStubTest.java | 97 ------------------- .../grpc/stub/AbstractBlockingStubTest.java | 97 ------------------- .../io/grpc/stub/AbstractFutureStubTest.java | 97 ------------------- .../java/io/grpc/stub/AbstractStubTest.java | 79 +++++++++++---- .../io/grpc/stub/BaseAbstractStubTest.java | 96 ------------------ .../testing/protobuf/SimpleServiceGrpc.java | 69 ++++++------- .../service/orca/v1/OpenRcaServiceGrpc.java | 69 ++++++------- .../api/v2/ClusterDiscoveryServiceGrpc.java | 69 ++++++------- .../api/v2/EndpointDiscoveryServiceGrpc.java | 69 ++++++------- .../api/v2/ListenerDiscoveryServiceGrpc.java | 69 ++++++------- .../api/v2/RouteDiscoveryServiceGrpc.java | 69 ++++++------- .../v2/ScopedRoutesDiscoveryServiceGrpc.java | 69 ++++++------- .../v2/VirtualHostDiscoveryServiceGrpc.java | 69 ++++++------- .../v2/AggregatedDiscoveryServiceGrpc.java | 69 ++++++------- .../v2/LoadReportingServiceGrpc.java | 69 ++++++------- 41 files changed, 947 insertions(+), 1910 deletions(-) delete mode 100644 stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java delete mode 100644 stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java delete mode 100644 stub/src/main/java/io/grpc/stub/AbstractFutureStub.java delete mode 100644 stub/src/main/java/io/grpc/stub/InternalClientCalls.java delete mode 100644 stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java delete mode 100644 stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java delete mode 100644 stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java delete mode 100644 stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java diff --git a/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java b/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java index 9f68246d9e0..a792853a45a 100644 --- a/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java +++ b/alts/src/generated/main/grpc/io/grpc/alts/internal/HandshakerServiceGrpc.java @@ -62,14 +62,7 @@ io.grpc.alts.internal.HandshakerResp> getDoHandshakeMethod() { * Creates a new async stub that supports all call types for the service */ public static HandshakerServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public HandshakerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new HandshakerServiceStub(channel, callOptions); - } - }; - return HandshakerServiceStub.newStub(factory, channel); + return new HandshakerServiceStub(channel); } /** @@ -77,14 +70,7 @@ public HandshakerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOption */ public static HandshakerServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public HandshakerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new HandshakerServiceBlockingStub(channel, callOptions); - } - }; - return HandshakerServiceBlockingStub.newStub(factory, channel); + return new HandshakerServiceBlockingStub(channel); } /** @@ -92,14 +78,7 @@ public HandshakerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.Ca */ public static HandshakerServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public HandshakerServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new HandshakerServiceFutureStub(channel, callOptions); - } - }; - return HandshakerServiceFutureStub.newStub(factory, channel); + return new HandshakerServiceFutureStub(channel); } /** @@ -136,15 +115,19 @@ public io.grpc.stub.StreamObserver doHandsh /** */ - public static final class HandshakerServiceStub extends io.grpc.stub.AbstractAsyncStub { - private HandshakerServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class HandshakerServiceStub extends io.grpc.stub.AbstractStub { + private HandshakerServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private HandshakerServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HandshakerServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected HandshakerServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new HandshakerServiceStub(channel, callOptions); } @@ -167,30 +150,38 @@ public io.grpc.stub.StreamObserver doHandsh /** */ - public static final class HandshakerServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private HandshakerServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class HandshakerServiceBlockingStub extends io.grpc.stub.AbstractStub { + private HandshakerServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private HandshakerServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HandshakerServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected HandshakerServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new HandshakerServiceBlockingStub(channel, callOptions); } } /** */ - public static final class HandshakerServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private HandshakerServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class HandshakerServiceFutureStub extends io.grpc.stub.AbstractStub { + private HandshakerServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private HandshakerServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HandshakerServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected HandshakerServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new HandshakerServiceFutureStub(channel, callOptions); } } diff --git a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java index 0ddf244e412..c7614532168 100644 --- a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java +++ b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/BenchmarkServiceGrpc.java @@ -186,14 +186,7 @@ io.grpc.benchmarks.proto.Messages.SimpleResponse> getStreamingBothWaysMethod() { * Creates a new async stub that supports all call types for the service */ public static BenchmarkServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public BenchmarkServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new BenchmarkServiceStub(channel, callOptions); - } - }; - return BenchmarkServiceStub.newStub(factory, channel); + return new BenchmarkServiceStub(channel); } /** @@ -201,14 +194,7 @@ public BenchmarkServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions */ public static BenchmarkServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public BenchmarkServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new BenchmarkServiceBlockingStub(channel, callOptions); - } - }; - return BenchmarkServiceBlockingStub.newStub(factory, channel); + return new BenchmarkServiceBlockingStub(channel); } /** @@ -216,14 +202,7 @@ public BenchmarkServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.Cal */ public static BenchmarkServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public BenchmarkServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new BenchmarkServiceFutureStub(channel, callOptions); - } - }; - return BenchmarkServiceFutureStub.newStub(factory, channel); + return new BenchmarkServiceFutureStub(channel); } /** @@ -329,15 +308,19 @@ public io.grpc.stub.StreamObserver { - private BenchmarkServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class BenchmarkServiceStub extends io.grpc.stub.AbstractStub { + private BenchmarkServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private BenchmarkServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected BenchmarkServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected BenchmarkServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new BenchmarkServiceStub(channel, callOptions); } @@ -405,15 +388,19 @@ public io.grpc.stub.StreamObserver { - private BenchmarkServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class BenchmarkServiceBlockingStub extends io.grpc.stub.AbstractStub { + private BenchmarkServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private BenchmarkServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected BenchmarkServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected BenchmarkServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new BenchmarkServiceBlockingStub(channel, callOptions); } @@ -443,15 +430,19 @@ public java.util.Iterator stre /** */ - public static final class BenchmarkServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private BenchmarkServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class BenchmarkServiceFutureStub extends io.grpc.stub.AbstractStub { + private BenchmarkServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private BenchmarkServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected BenchmarkServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected BenchmarkServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new BenchmarkServiceFutureStub(channel, callOptions); } diff --git a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java index 8ccaf01fad9..3bd2bdb96b0 100644 --- a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java +++ b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/ReportQpsScenarioServiceGrpc.java @@ -62,14 +62,7 @@ io.grpc.benchmarks.proto.Control.Void> getReportScenarioMethod() { * Creates a new async stub that supports all call types for the service */ public static ReportQpsScenarioServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReportQpsScenarioServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReportQpsScenarioServiceStub(channel, callOptions); - } - }; - return ReportQpsScenarioServiceStub.newStub(factory, channel); + return new ReportQpsScenarioServiceStub(channel); } /** @@ -77,14 +70,7 @@ public ReportQpsScenarioServiceStub newStub(io.grpc.Channel channel, io.grpc.Cal */ public static ReportQpsScenarioServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReportQpsScenarioServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReportQpsScenarioServiceBlockingStub(channel, callOptions); - } - }; - return ReportQpsScenarioServiceBlockingStub.newStub(factory, channel); + return new ReportQpsScenarioServiceBlockingStub(channel); } /** @@ -92,14 +78,7 @@ public ReportQpsScenarioServiceBlockingStub newStub(io.grpc.Channel channel, io. */ public static ReportQpsScenarioServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReportQpsScenarioServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReportQpsScenarioServiceFutureStub(channel, callOptions); - } - }; - return ReportQpsScenarioServiceFutureStub.newStub(factory, channel); + return new ReportQpsScenarioServiceFutureStub(channel); } /** @@ -131,15 +110,19 @@ public void reportScenario(io.grpc.benchmarks.proto.Control.ScenarioResult reque /** */ - public static final class ReportQpsScenarioServiceStub extends io.grpc.stub.AbstractAsyncStub { - private ReportQpsScenarioServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReportQpsScenarioServiceStub extends io.grpc.stub.AbstractStub { + private ReportQpsScenarioServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private ReportQpsScenarioServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReportQpsScenarioServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReportQpsScenarioServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReportQpsScenarioServiceStub(channel, callOptions); } @@ -157,15 +140,19 @@ public void reportScenario(io.grpc.benchmarks.proto.Control.ScenarioResult reque /** */ - public static final class ReportQpsScenarioServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ReportQpsScenarioServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReportQpsScenarioServiceBlockingStub extends io.grpc.stub.AbstractStub { + private ReportQpsScenarioServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ReportQpsScenarioServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReportQpsScenarioServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReportQpsScenarioServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReportQpsScenarioServiceBlockingStub(channel, callOptions); } @@ -182,15 +169,19 @@ public io.grpc.benchmarks.proto.Control.Void reportScenario(io.grpc.benchmarks.p /** */ - public static final class ReportQpsScenarioServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private ReportQpsScenarioServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReportQpsScenarioServiceFutureStub extends io.grpc.stub.AbstractStub { + private ReportQpsScenarioServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ReportQpsScenarioServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReportQpsScenarioServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReportQpsScenarioServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReportQpsScenarioServiceFutureStub(channel, callOptions); } diff --git a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java index 9fc781c24b5..05e85553c4b 100644 --- a/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java +++ b/benchmarks/src/generated/main/grpc/io/grpc/benchmarks/proto/WorkerServiceGrpc.java @@ -155,14 +155,7 @@ io.grpc.benchmarks.proto.Control.Void> getQuitWorkerMethod() { * Creates a new async stub that supports all call types for the service */ public static WorkerServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public WorkerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new WorkerServiceStub(channel, callOptions); - } - }; - return WorkerServiceStub.newStub(factory, channel); + return new WorkerServiceStub(channel); } /** @@ -170,14 +163,7 @@ public WorkerServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions ca */ public static WorkerServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public WorkerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new WorkerServiceBlockingStub(channel, callOptions); - } - }; - return WorkerServiceBlockingStub.newStub(factory, channel); + return new WorkerServiceBlockingStub(channel); } /** @@ -185,14 +171,7 @@ public WorkerServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOp */ public static WorkerServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public WorkerServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new WorkerServiceFutureStub(channel, callOptions); - } - }; - return WorkerServiceFutureStub.newStub(factory, channel); + return new WorkerServiceFutureStub(channel); } /** @@ -285,15 +264,19 @@ public void quitWorker(io.grpc.benchmarks.proto.Control.Void request, /** */ - public static final class WorkerServiceStub extends io.grpc.stub.AbstractAsyncStub { - private WorkerServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class WorkerServiceStub extends io.grpc.stub.AbstractStub { + private WorkerServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private WorkerServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected WorkerServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected WorkerServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new WorkerServiceStub(channel, callOptions); } @@ -354,15 +337,19 @@ public void quitWorker(io.grpc.benchmarks.proto.Control.Void request, /** */ - public static final class WorkerServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private WorkerServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class WorkerServiceBlockingStub extends io.grpc.stub.AbstractStub { + private WorkerServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private WorkerServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected WorkerServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected WorkerServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new WorkerServiceBlockingStub(channel, callOptions); } @@ -389,15 +376,19 @@ public io.grpc.benchmarks.proto.Control.Void quitWorker(io.grpc.benchmarks.proto /** */ - public static final class WorkerServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private WorkerServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class WorkerServiceFutureStub extends io.grpc.stub.AbstractStub { + private WorkerServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private WorkerServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected WorkerServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected WorkerServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new WorkerServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/java_plugin/cpp/java_generator.cpp b/compiler/src/java_plugin/cpp/java_generator.cpp index 5232f11fa53..fbe4a65dfc7 100644 --- a/compiler/src/java_plugin/cpp/java_generator.cpp +++ b/compiler/src/java_plugin/cpp/java_generator.cpp @@ -489,37 +489,6 @@ static void PrintBindServiceMethodBody(const ServiceDescriptor* service, std::map* vars, Printer* p); -// Prints a StubFactory for given service / stub type. -static void PrintStubFactory( - const ServiceDescriptor* service, - std::map* vars, - Printer* p, StubType type) { - string stub_type_name; - switch (type) { - case ASYNC_CLIENT_IMPL: - stub_type_name = ""; - break; - case FUTURE_CLIENT_IMPL: - stub_type_name = "Future"; - break; - case BLOCKING_CLIENT_IMPL: - stub_type_name = "Blocking"; - break; - default: - GRPC_CODEGEN_FAIL << "Cannot generate StubFactory for StubType: " << type; - } - (*vars)["stub_full_name"] = (*vars)["service_name"] + stub_type_name + "Stub"; - p->Print( - *vars, - "$StubFactory$<$stub_full_name$> factory =\n" - " new $StubFactory$<$stub_full_name$>() {\n" - " @$Override$\n" - " public $stub_full_name$ newStub($Channel$ channel, $CallOptions$ callOptions) {\n" - " return new $stub_full_name$(channel, callOptions);\n" - " }\n" - " };\n"); -} - // Prints a client interface or implementation class, or a server interface. static void PrintStub( const ServiceDescriptor* service, @@ -530,7 +499,6 @@ static void PrintStub( (*vars)["abstract_name"] = service_name + "ImplBase"; string stub_name = service_name; string client_name = service_name; - string stub_base_class_name = "AbstractStub"; CallType call_type; bool impl_base = false; bool interface = false; @@ -542,7 +510,6 @@ static void PrintStub( case ASYNC_CLIENT_IMPL: call_type = ASYNC_CALL; stub_name += "Stub"; - stub_base_class_name = "AbstractAsyncStub"; break; case BLOCKING_CLIENT_INTERFACE: interface = true; @@ -551,7 +518,6 @@ static void PrintStub( call_type = BLOCKING_CALL; stub_name += "BlockingStub"; client_name += "BlockingClient"; - stub_base_class_name = "AbstractBlockingStub"; break; case FUTURE_CLIENT_INTERFACE: interface = true; @@ -560,20 +526,16 @@ static void PrintStub( call_type = FUTURE_CALL; stub_name += "FutureStub"; client_name += "FutureClient"; - stub_base_class_name = "AbstractFutureStub"; break; case ASYNC_INTERFACE: call_type = ASYNC_CALL; interface = true; - stub_name += "Stub"; - stub_base_class_name = "AbstractAsyncStub"; break; default: GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type; } (*vars)["stub_name"] = stub_name; (*vars)["client_name"] = client_name; - (*vars)["stub_base_class_name"] = (*vars)[stub_base_class_name]; // Class head if (!interface) { @@ -587,13 +549,11 @@ static void PrintStub( if (impl_base) { p->Print( *vars, - "public static abstract class $abstract_name$" - " implements $BindableService$ {\n"); + "public static abstract class $abstract_name$ implements $BindableService$ {\n"); } else { p->Print( *vars, - "public static final class $stub_name$" - " extends $stub_base_class_name$<$stub_name$> {\n"); + "public static final class $stub_name$ extends $AbstractStub$<$stub_name$> {\n"); } p->Indent(); @@ -601,9 +561,15 @@ static void PrintStub( if (!impl_base && !interface) { p->Print( *vars, - "private $stub_name$(\n" - " $Channel$ channel, $CallOptions$ callOptions) {" - "\n"); + "private $stub_name$($Channel$ channel) {\n"); + p->Indent(); + p->Print("super(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + p->Print( + *vars, + "private $stub_name$($Channel$ channel,\n" + " $CallOptions$ callOptions) {\n"); p->Indent(); p->Print("super(channel, callOptions);\n"); p->Outdent(); @@ -611,9 +577,8 @@ static void PrintStub( p->Print( *vars, "@$Override$\n" - "protected $stub_name$ build(\n" - " $Channel$ channel, $CallOptions$ callOptions) {" - "\n"); + "protected $stub_name$ build($Channel$ channel,\n" + " $CallOptions$ callOptions) {\n"); p->Indent(); p->Print( *vars, @@ -1111,8 +1076,9 @@ static void PrintService(const ServiceDescriptor* service, *vars, "public static $service_name$Stub newStub($Channel$ channel) {\n"); p->Indent(); - PrintStubFactory(service, vars, p, ASYNC_CLIENT_IMPL); - p->Print(*vars, "return $service_name$Stub.newStub(factory, channel);\n"); + p->Print( + *vars, + "return new $service_name$Stub(channel);\n"); p->Outdent(); p->Print("}\n\n"); @@ -1124,10 +1090,9 @@ static void PrintService(const ServiceDescriptor* service, "public static $service_name$BlockingStub newBlockingStub(\n" " $Channel$ channel) {\n"); p->Indent(); - PrintStubFactory(service, vars, p, BLOCKING_CLIENT_IMPL); p->Print( *vars, - "return $service_name$BlockingStub.newStub(factory, channel);\n"); + "return new $service_name$BlockingStub(channel);\n"); p->Outdent(); p->Print("}\n\n"); @@ -1139,10 +1104,9 @@ static void PrintService(const ServiceDescriptor* service, "public static $service_name$FutureStub newFutureStub(\n" " $Channel$ channel) {\n"); p->Indent(); - PrintStubFactory(service, vars, p, FUTURE_CLIENT_IMPL); p->Print( *vars, - "return $service_name$FutureStub.newStub(factory, channel);\n"); + "return new $service_name$FutureStub(channel);\n"); p->Outdent(); p->Print("}\n\n"); @@ -1216,10 +1180,6 @@ void GenerateService(const ServiceDescriptor* service, vars["ProtoMethodDescriptorSupplier"] = "io.grpc.protobuf.ProtoMethodDescriptorSupplier"; vars["AbstractStub"] = "io.grpc.stub.AbstractStub"; - vars["AbstractAsyncStub"] = "io.grpc.stub.AbstractAsyncStub"; - vars["AbstractFutureStub"] = "io.grpc.stub.AbstractFutureStub"; - vars["AbstractBlockingStub"] = "io.grpc.stub.AbstractBlockingStub"; - vars["StubFactory"] = "io.grpc.stub.AbstractStub.StubFactory"; vars["RpcMethod"] = "io.grpc.stub.annotations.RpcMethod"; vars["MethodDescriptor"] = "io.grpc.MethodDescriptor"; vars["StreamObserver"] = "io.grpc.stub.StreamObserver"; diff --git a/compiler/src/test/golden/TestDeprecatedService.java.txt b/compiler/src/test/golden/TestDeprecatedService.java.txt index 4002f504e66..a57999ac0b8 100644 --- a/compiler/src/test/golden/TestDeprecatedService.java.txt +++ b/compiler/src/test/golden/TestDeprecatedService.java.txt @@ -66,14 +66,7 @@ public final class TestDeprecatedServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestDeprecatedServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestDeprecatedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestDeprecatedServiceStub(channel, callOptions); - } - }; - return TestDeprecatedServiceStub.newStub(factory, channel); + return new TestDeprecatedServiceStub(channel); } /** @@ -81,14 +74,7 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestDeprecatedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestDeprecatedServiceBlockingStub(channel, callOptions); - } - }; - return TestDeprecatedServiceBlockingStub.newStub(factory, channel); + return new TestDeprecatedServiceBlockingStub(channel); } /** @@ -96,14 +82,7 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestDeprecatedServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestDeprecatedServiceFutureStub(channel, callOptions); - } - }; - return TestDeprecatedServiceFutureStub.newStub(factory, channel); + return new TestDeprecatedServiceFutureStub(channel); } /** @@ -144,15 +123,19 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractAsyncStub { - private TestDeprecatedServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractStub { + private TestDeprecatedServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private TestDeprecatedServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceStub(channel, callOptions); } @@ -175,15 +158,19 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private TestDeprecatedServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractStub { + private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceBlockingStub(channel, callOptions); } @@ -205,15 +192,19 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private TestDeprecatedServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractStub { + private TestDeprecatedServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private TestDeprecatedServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index 5268ee46b5d..b6324715568 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -284,14 +284,7 @@ public final class TestServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceStub(channel, callOptions); - } - }; - return TestServiceStub.newStub(factory, channel); + return new TestServiceStub(channel); } /** @@ -299,14 +292,7 @@ public final class TestServiceGrpc { */ public static TestServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceBlockingStub(channel, callOptions); - } - }; - return TestServiceBlockingStub.newStub(factory, channel); + return new TestServiceBlockingStub(channel); } /** @@ -314,14 +300,7 @@ public final class TestServiceGrpc { */ public static TestServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceFutureStub(channel, callOptions); - } - }; - return TestServiceFutureStub.newStub(factory, channel); + return new TestServiceFutureStub(channel); } /** @@ -487,15 +466,19 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceStub extends io.grpc.stub.AbstractAsyncStub { - private TestServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceStub extends io.grpc.stub.AbstractStub { + private TestServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceStub(channel, callOptions); } @@ -602,15 +585,19 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private TestServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractStub { + private TestServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceBlockingStub(channel, callOptions); } @@ -663,15 +650,19 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private TestServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceFutureStub extends io.grpc.stub.AbstractStub { + private TestServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/testLite/golden/TestDeprecatedService.java.txt b/compiler/src/testLite/golden/TestDeprecatedService.java.txt index cc2ecb80671..6d59a415592 100644 --- a/compiler/src/testLite/golden/TestDeprecatedService.java.txt +++ b/compiler/src/testLite/golden/TestDeprecatedService.java.txt @@ -65,14 +65,7 @@ public final class TestDeprecatedServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestDeprecatedServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestDeprecatedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestDeprecatedServiceStub(channel, callOptions); - } - }; - return TestDeprecatedServiceStub.newStub(factory, channel); + return new TestDeprecatedServiceStub(channel); } /** @@ -80,14 +73,7 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestDeprecatedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestDeprecatedServiceBlockingStub(channel, callOptions); - } - }; - return TestDeprecatedServiceBlockingStub.newStub(factory, channel); + return new TestDeprecatedServiceBlockingStub(channel); } /** @@ -95,14 +81,7 @@ public final class TestDeprecatedServiceGrpc { */ public static TestDeprecatedServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestDeprecatedServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestDeprecatedServiceFutureStub(channel, callOptions); - } - }; - return TestDeprecatedServiceFutureStub.newStub(factory, channel); + return new TestDeprecatedServiceFutureStub(channel); } /** @@ -143,15 +122,19 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractAsyncStub { - private TestDeprecatedServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceStub extends io.grpc.stub.AbstractStub { + private TestDeprecatedServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private TestDeprecatedServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceStub(channel, callOptions); } @@ -174,15 +157,19 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private TestDeprecatedServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceBlockingStub extends io.grpc.stub.AbstractStub { + private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private TestDeprecatedServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceBlockingStub(channel, callOptions); } @@ -204,15 +191,19 @@ public final class TestDeprecatedServiceGrpc { * */ @java.lang.Deprecated - public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private TestDeprecatedServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestDeprecatedServiceFutureStub extends io.grpc.stub.AbstractStub { + private TestDeprecatedServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private TestDeprecatedServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestDeprecatedServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestDeprecatedServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestDeprecatedServiceFutureStub(channel, callOptions); } diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt index c0d17510db6..2bd085fbc19 100644 --- a/compiler/src/testLite/golden/TestService.java.txt +++ b/compiler/src/testLite/golden/TestService.java.txt @@ -276,14 +276,7 @@ public final class TestServiceGrpc { * Creates a new async stub that supports all call types for the service */ public static TestServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceStub(channel, callOptions); - } - }; - return TestServiceStub.newStub(factory, channel); + return new TestServiceStub(channel); } /** @@ -291,14 +284,7 @@ public final class TestServiceGrpc { */ public static TestServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceBlockingStub(channel, callOptions); - } - }; - return TestServiceBlockingStub.newStub(factory, channel); + return new TestServiceBlockingStub(channel); } /** @@ -306,14 +292,7 @@ public final class TestServiceGrpc { */ public static TestServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceFutureStub(channel, callOptions); - } - }; - return TestServiceFutureStub.newStub(factory, channel); + return new TestServiceFutureStub(channel); } /** @@ -479,15 +458,19 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceStub extends io.grpc.stub.AbstractAsyncStub { - private TestServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceStub extends io.grpc.stub.AbstractStub { + private TestServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceStub(channel, callOptions); } @@ -594,15 +577,19 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private TestServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractStub { + private TestServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceBlockingStub(channel, callOptions); } @@ -655,15 +642,19 @@ public final class TestServiceGrpc { * Test service that supports all call types. * */ - public static final class TestServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private TestServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceFutureStub extends io.grpc.stub.AbstractStub { + private TestServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceFutureStub(channel, callOptions); } diff --git a/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java b/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java index 4c40b2a0f4b..4d3ad18be2b 100644 --- a/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java +++ b/grpclb/src/generated/main/grpc/io/grpc/lb/v1/LoadBalancerGrpc.java @@ -62,14 +62,7 @@ io.grpc.lb.v1.LoadBalanceResponse> getBalanceLoadMethod() { * Creates a new async stub that supports all call types for the service */ public static LoadBalancerStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LoadBalancerStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LoadBalancerStub(channel, callOptions); - } - }; - return LoadBalancerStub.newStub(factory, channel); + return new LoadBalancerStub(channel); } /** @@ -77,14 +70,7 @@ public LoadBalancerStub newStub(io.grpc.Channel channel, io.grpc.CallOptions cal */ public static LoadBalancerBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LoadBalancerBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LoadBalancerBlockingStub(channel, callOptions); - } - }; - return LoadBalancerBlockingStub.newStub(factory, channel); + return new LoadBalancerBlockingStub(channel); } /** @@ -92,14 +78,7 @@ public LoadBalancerBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOpt */ public static LoadBalancerFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LoadBalancerFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LoadBalancerFutureStub(channel, callOptions); - } - }; - return LoadBalancerFutureStub.newStub(factory, channel); + return new LoadBalancerFutureStub(channel); } /** @@ -131,15 +110,19 @@ public io.grpc.stub.StreamObserver balanceLoad /** */ - public static final class LoadBalancerStub extends io.grpc.stub.AbstractAsyncStub { - private LoadBalancerStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class LoadBalancerStub extends io.grpc.stub.AbstractStub { + private LoadBalancerStub(io.grpc.Channel channel) { + super(channel); + } + + private LoadBalancerStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadBalancerStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected LoadBalancerStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new LoadBalancerStub(channel, callOptions); } @@ -157,30 +140,38 @@ public io.grpc.stub.StreamObserver balanceLoad /** */ - public static final class LoadBalancerBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private LoadBalancerBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class LoadBalancerBlockingStub extends io.grpc.stub.AbstractStub { + private LoadBalancerBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private LoadBalancerBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadBalancerBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected LoadBalancerBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new LoadBalancerBlockingStub(channel, callOptions); } } /** */ - public static final class LoadBalancerFutureStub extends io.grpc.stub.AbstractFutureStub { - private LoadBalancerFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class LoadBalancerFutureStub extends io.grpc.stub.AbstractStub { + private LoadBalancerFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private LoadBalancerFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadBalancerFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected LoadBalancerFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new LoadBalancerFutureStub(channel, callOptions); } } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java index e6c7fcc92bc..2978f9c8cc8 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/MetricsServiceGrpc.java @@ -93,14 +93,7 @@ io.grpc.testing.integration.Metrics.GaugeResponse> getGetGaugeMethod() { * Creates a new async stub that supports all call types for the service */ public static MetricsServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public MetricsServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new MetricsServiceStub(channel, callOptions); - } - }; - return MetricsServiceStub.newStub(factory, channel); + return new MetricsServiceStub(channel); } /** @@ -108,14 +101,7 @@ public MetricsServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions c */ public static MetricsServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public MetricsServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new MetricsServiceBlockingStub(channel, callOptions); - } - }; - return MetricsServiceBlockingStub.newStub(factory, channel); + return new MetricsServiceBlockingStub(channel); } /** @@ -123,14 +109,7 @@ public MetricsServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallO */ public static MetricsServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public MetricsServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new MetricsServiceFutureStub(channel, callOptions); - } - }; - return MetricsServiceFutureStub.newStub(factory, channel); + return new MetricsServiceFutureStub(channel); } /** @@ -180,15 +159,19 @@ public void getGauge(io.grpc.testing.integration.Metrics.GaugeRequest request, /** */ - public static final class MetricsServiceStub extends io.grpc.stub.AbstractAsyncStub { - private MetricsServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class MetricsServiceStub extends io.grpc.stub.AbstractStub { + private MetricsServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private MetricsServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected MetricsServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected MetricsServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new MetricsServiceStub(channel, callOptions); } @@ -218,15 +201,19 @@ public void getGauge(io.grpc.testing.integration.Metrics.GaugeRequest request, /** */ - public static final class MetricsServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private MetricsServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class MetricsServiceBlockingStub extends io.grpc.stub.AbstractStub { + private MetricsServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private MetricsServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected MetricsServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected MetricsServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new MetricsServiceBlockingStub(channel, callOptions); } @@ -255,15 +242,19 @@ public io.grpc.testing.integration.Metrics.GaugeResponse getGauge(io.grpc.testin /** */ - public static final class MetricsServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private MetricsServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class MetricsServiceFutureStub extends io.grpc.stub.AbstractStub { + private MetricsServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private MetricsServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected MetricsServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected MetricsServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new MetricsServiceFutureStub(channel, callOptions); } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java index 50d29d481f5..6ecd3208e30 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/ReconnectServiceGrpc.java @@ -96,14 +96,7 @@ io.grpc.testing.integration.Messages.ReconnectInfo> getStopMethod() { * Creates a new async stub that supports all call types for the service */ public static ReconnectServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReconnectServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReconnectServiceStub(channel, callOptions); - } - }; - return ReconnectServiceStub.newStub(factory, channel); + return new ReconnectServiceStub(channel); } /** @@ -111,14 +104,7 @@ public ReconnectServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions */ public static ReconnectServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReconnectServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReconnectServiceBlockingStub(channel, callOptions); - } - }; - return ReconnectServiceBlockingStub.newStub(factory, channel); + return new ReconnectServiceBlockingStub(channel); } /** @@ -126,14 +112,7 @@ public ReconnectServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.Cal */ public static ReconnectServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReconnectServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReconnectServiceFutureStub(channel, callOptions); - } - }; - return ReconnectServiceFutureStub.newStub(factory, channel); + return new ReconnectServiceFutureStub(channel); } /** @@ -182,15 +161,19 @@ public void stop(io.grpc.testing.integration.EmptyProtos.Empty request, * A service used to control reconnect server. * */ - public static final class ReconnectServiceStub extends io.grpc.stub.AbstractAsyncStub { - private ReconnectServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReconnectServiceStub extends io.grpc.stub.AbstractStub { + private ReconnectServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private ReconnectServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReconnectServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReconnectServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReconnectServiceStub(channel, callOptions); } @@ -216,15 +199,19 @@ public void stop(io.grpc.testing.integration.EmptyProtos.Empty request, * A service used to control reconnect server. * */ - public static final class ReconnectServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ReconnectServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReconnectServiceBlockingStub extends io.grpc.stub.AbstractStub { + private ReconnectServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ReconnectServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReconnectServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReconnectServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReconnectServiceBlockingStub(channel, callOptions); } @@ -248,15 +235,19 @@ public io.grpc.testing.integration.Messages.ReconnectInfo stop(io.grpc.testing.i * A service used to control reconnect server. * */ - public static final class ReconnectServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private ReconnectServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReconnectServiceFutureStub extends io.grpc.stub.AbstractStub { + private ReconnectServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ReconnectServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReconnectServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReconnectServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReconnectServiceFutureStub(channel, callOptions); } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java index e300c5f6b20..faa8925faa8 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/TestServiceGrpc.java @@ -283,14 +283,7 @@ io.grpc.testing.integration.EmptyProtos.Empty> getUnimplementedCallMethod() { * Creates a new async stub that supports all call types for the service */ public static TestServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceStub(channel, callOptions); - } - }; - return TestServiceStub.newStub(factory, channel); + return new TestServiceStub(channel); } /** @@ -298,14 +291,7 @@ public TestServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions call */ public static TestServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceBlockingStub(channel, callOptions); - } - }; - return TestServiceBlockingStub.newStub(factory, channel); + return new TestServiceBlockingStub(channel); } /** @@ -313,14 +299,7 @@ public TestServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOpti */ public static TestServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public TestServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new TestServiceFutureStub(channel, callOptions); - } - }; - return TestServiceFutureStub.newStub(factory, channel); + return new TestServiceFutureStub(channel); } /** @@ -489,15 +468,19 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * performance with various types of payload. * */ - public static final class TestServiceStub extends io.grpc.stub.AbstractAsyncStub { - private TestServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceStub extends io.grpc.stub.AbstractStub { + private TestServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceStub(channel, callOptions); } @@ -606,15 +589,19 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * performance with various types of payload. * */ - public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private TestServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceBlockingStub extends io.grpc.stub.AbstractStub { + private TestServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceBlockingStub(channel, callOptions); } @@ -680,15 +667,19 @@ public io.grpc.testing.integration.EmptyProtos.Empty unimplementedCall(io.grpc.t * performance with various types of payload. * */ - public static final class TestServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private TestServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class TestServiceFutureStub extends io.grpc.stub.AbstractStub { + private TestServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private TestServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected TestServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected TestServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new TestServiceFutureStub(channel, callOptions); } diff --git a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java index 09cd8e9ef13..156321975d6 100644 --- a/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java +++ b/interop-testing/src/generated/main/grpc/io/grpc/testing/integration/UnimplementedServiceGrpc.java @@ -66,14 +66,7 @@ io.grpc.testing.integration.EmptyProtos.Empty> getUnimplementedCallMethod() { * Creates a new async stub that supports all call types for the service */ public static UnimplementedServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public UnimplementedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new UnimplementedServiceStub(channel, callOptions); - } - }; - return UnimplementedServiceStub.newStub(factory, channel); + return new UnimplementedServiceStub(channel); } /** @@ -81,14 +74,7 @@ public UnimplementedServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOpt */ public static UnimplementedServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public UnimplementedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new UnimplementedServiceBlockingStub(channel, callOptions); - } - }; - return UnimplementedServiceBlockingStub.newStub(factory, channel); + return new UnimplementedServiceBlockingStub(channel); } /** @@ -96,14 +82,7 @@ public UnimplementedServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc */ public static UnimplementedServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public UnimplementedServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new UnimplementedServiceFutureStub(channel, callOptions); - } - }; - return UnimplementedServiceFutureStub.newStub(factory, channel); + return new UnimplementedServiceFutureStub(channel); } /** @@ -143,15 +122,19 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * that case. * */ - public static final class UnimplementedServiceStub extends io.grpc.stub.AbstractAsyncStub { - private UnimplementedServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class UnimplementedServiceStub extends io.grpc.stub.AbstractStub { + private UnimplementedServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private UnimplementedServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected UnimplementedServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected UnimplementedServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new UnimplementedServiceStub(channel, callOptions); } @@ -173,15 +156,19 @@ public void unimplementedCall(io.grpc.testing.integration.EmptyProtos.Empty requ * that case. * */ - public static final class UnimplementedServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private UnimplementedServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class UnimplementedServiceBlockingStub extends io.grpc.stub.AbstractStub { + private UnimplementedServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private UnimplementedServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected UnimplementedServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected UnimplementedServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new UnimplementedServiceBlockingStub(channel, callOptions); } @@ -202,15 +189,19 @@ public io.grpc.testing.integration.EmptyProtos.Empty unimplementedCall(io.grpc.t * that case. * */ - public static final class UnimplementedServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private UnimplementedServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class UnimplementedServiceFutureStub extends io.grpc.stub.AbstractStub { + private UnimplementedServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private UnimplementedServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected UnimplementedServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected UnimplementedServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new UnimplementedServiceFutureStub(channel, callOptions); } diff --git a/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java b/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java index d45eb53587e..165eec264e1 100644 --- a/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java +++ b/services/src/generated/main/grpc/io/grpc/channelz/v1/ChannelzGrpc.java @@ -252,14 +252,7 @@ io.grpc.channelz.v1.GetSocketResponse> getGetSocketMethod() { * Creates a new async stub that supports all call types for the service */ public static ChannelzStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ChannelzStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ChannelzStub(channel, callOptions); - } - }; - return ChannelzStub.newStub(factory, channel); + return new ChannelzStub(channel); } /** @@ -267,14 +260,7 @@ public ChannelzStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOpt */ public static ChannelzBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ChannelzBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ChannelzBlockingStub(channel, callOptions); - } - }; - return ChannelzBlockingStub.newStub(factory, channel); + return new ChannelzBlockingStub(channel); } /** @@ -282,14 +268,7 @@ public ChannelzBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions */ public static ChannelzFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ChannelzFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ChannelzFutureStub(channel, callOptions); - } - }; - return ChannelzFutureStub.newStub(factory, channel); + return new ChannelzFutureStub(channel); } /** @@ -432,15 +411,19 @@ public void getSocket(io.grpc.channelz.v1.GetSocketRequest request, * information. * */ - public static final class ChannelzStub extends io.grpc.stub.AbstractAsyncStub { - private ChannelzStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ChannelzStub extends io.grpc.stub.AbstractStub { + private ChannelzStub(io.grpc.Channel channel) { + super(channel); + } + + private ChannelzStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ChannelzStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ChannelzStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ChannelzStub(channel, callOptions); } @@ -529,15 +512,19 @@ public void getSocket(io.grpc.channelz.v1.GetSocketRequest request, * information. * */ - public static final class ChannelzBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ChannelzBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ChannelzBlockingStub extends io.grpc.stub.AbstractStub { + private ChannelzBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ChannelzBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ChannelzBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ChannelzBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ChannelzBlockingStub(channel, callOptions); } @@ -619,15 +606,19 @@ public io.grpc.channelz.v1.GetSocketResponse getSocket(io.grpc.channelz.v1.GetSo * information. * */ - public static final class ChannelzFutureStub extends io.grpc.stub.AbstractFutureStub { - private ChannelzFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ChannelzFutureStub extends io.grpc.stub.AbstractStub { + private ChannelzFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ChannelzFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ChannelzFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ChannelzFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ChannelzFutureStub(channel, callOptions); } diff --git a/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java b/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java index 14457d12c7f..93b8abb28ef 100644 --- a/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java +++ b/services/src/generated/main/grpc/io/grpc/health/v1/HealthGrpc.java @@ -93,14 +93,7 @@ io.grpc.health.v1.HealthCheckResponse> getWatchMethod() { * Creates a new async stub that supports all call types for the service */ public static HealthStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public HealthStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new HealthStub(channel, callOptions); - } - }; - return HealthStub.newStub(factory, channel); + return new HealthStub(channel); } /** @@ -108,14 +101,7 @@ public HealthStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptio */ public static HealthBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public HealthBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new HealthBlockingStub(channel, callOptions); - } - }; - return HealthBlockingStub.newStub(factory, channel); + return new HealthBlockingStub(channel); } /** @@ -123,14 +109,7 @@ public HealthBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions c */ public static HealthFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public HealthFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new HealthFutureStub(channel, callOptions); - } - }; - return HealthFutureStub.newStub(factory, channel); + return new HealthFutureStub(channel); } /** @@ -192,15 +171,19 @@ public void watch(io.grpc.health.v1.HealthCheckRequest request, /** */ - public static final class HealthStub extends io.grpc.stub.AbstractAsyncStub { - private HealthStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class HealthStub extends io.grpc.stub.AbstractStub { + private HealthStub(io.grpc.Channel channel) { + super(channel); + } + + private HealthStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HealthStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected HealthStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new HealthStub(channel, callOptions); } @@ -242,15 +225,19 @@ public void watch(io.grpc.health.v1.HealthCheckRequest request, /** */ - public static final class HealthBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private HealthBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class HealthBlockingStub extends io.grpc.stub.AbstractStub { + private HealthBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private HealthBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HealthBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected HealthBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new HealthBlockingStub(channel, callOptions); } @@ -291,15 +278,19 @@ public java.util.Iterator watch( /** */ - public static final class HealthFutureStub extends io.grpc.stub.AbstractFutureStub { - private HealthFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class HealthFutureStub extends io.grpc.stub.AbstractStub { + private HealthFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private HealthFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected HealthFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected HealthFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new HealthFutureStub(channel, callOptions); } diff --git a/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java b/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java index f85cbfdba70..035d177e2d5 100644 --- a/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java +++ b/services/src/generated/main/grpc/io/grpc/reflection/v1alpha/ServerReflectionGrpc.java @@ -62,14 +62,7 @@ io.grpc.reflection.v1alpha.ServerReflectionResponse> getServerReflectionInfoMeth * Creates a new async stub that supports all call types for the service */ public static ServerReflectionStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ServerReflectionStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ServerReflectionStub(channel, callOptions); - } - }; - return ServerReflectionStub.newStub(factory, channel); + return new ServerReflectionStub(channel); } /** @@ -77,14 +70,7 @@ public ServerReflectionStub newStub(io.grpc.Channel channel, io.grpc.CallOptions */ public static ServerReflectionBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ServerReflectionBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ServerReflectionBlockingStub(channel, callOptions); - } - }; - return ServerReflectionBlockingStub.newStub(factory, channel); + return new ServerReflectionBlockingStub(channel); } /** @@ -92,14 +78,7 @@ public ServerReflectionBlockingStub newStub(io.grpc.Channel channel, io.grpc.Cal */ public static ServerReflectionFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ServerReflectionFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ServerReflectionFutureStub(channel, callOptions); - } - }; - return ServerReflectionFutureStub.newStub(factory, channel); + return new ServerReflectionFutureStub(channel); } /** @@ -132,15 +111,19 @@ public io.grpc.stub.StreamObserver { - private ServerReflectionStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ServerReflectionStub extends io.grpc.stub.AbstractStub { + private ServerReflectionStub(io.grpc.Channel channel) { + super(channel); + } + + private ServerReflectionStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ServerReflectionStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ServerReflectionStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ServerReflectionStub(channel, callOptions); } @@ -159,30 +142,38 @@ public io.grpc.stub.StreamObserver { - private ServerReflectionBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ServerReflectionBlockingStub extends io.grpc.stub.AbstractStub { + private ServerReflectionBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ServerReflectionBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ServerReflectionBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ServerReflectionBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ServerReflectionBlockingStub(channel, callOptions); } } /** */ - public static final class ServerReflectionFutureStub extends io.grpc.stub.AbstractFutureStub { - private ServerReflectionFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ServerReflectionFutureStub extends io.grpc.stub.AbstractStub { + private ServerReflectionFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ServerReflectionFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ServerReflectionFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ServerReflectionFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ServerReflectionFutureStub(channel, callOptions); } } diff --git a/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java b/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java index be673b3939c..1b5ab5c12cb 100644 --- a/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java +++ b/services/src/generated/test/grpc/io/grpc/reflection/testing/AnotherDynamicServiceGrpc.java @@ -65,14 +65,7 @@ io.grpc.reflection.testing.DynamicReply> getMethodMethod() { * Creates a new async stub that supports all call types for the service */ public static AnotherDynamicServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public AnotherDynamicServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new AnotherDynamicServiceStub(channel, callOptions); - } - }; - return AnotherDynamicServiceStub.newStub(factory, channel); + return new AnotherDynamicServiceStub(channel); } /** @@ -80,14 +73,7 @@ public AnotherDynamicServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOp */ public static AnotherDynamicServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public AnotherDynamicServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new AnotherDynamicServiceBlockingStub(channel, callOptions); - } - }; - return AnotherDynamicServiceBlockingStub.newStub(factory, channel); + return new AnotherDynamicServiceBlockingStub(channel); } /** @@ -95,14 +81,7 @@ public AnotherDynamicServiceBlockingStub newStub(io.grpc.Channel channel, io.grp */ public static AnotherDynamicServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public AnotherDynamicServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new AnotherDynamicServiceFutureStub(channel, callOptions); - } - }; - return AnotherDynamicServiceFutureStub.newStub(factory, channel); + return new AnotherDynamicServiceFutureStub(channel); } /** @@ -140,15 +119,19 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * AnotherDynamicService * */ - public static final class AnotherDynamicServiceStub extends io.grpc.stub.AbstractAsyncStub { - private AnotherDynamicServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class AnotherDynamicServiceStub extends io.grpc.stub.AbstractStub { + private AnotherDynamicServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private AnotherDynamicServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AnotherDynamicServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected AnotherDynamicServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new AnotherDynamicServiceStub(channel, callOptions); } @@ -169,15 +152,19 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * AnotherDynamicService * */ - public static final class AnotherDynamicServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private AnotherDynamicServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class AnotherDynamicServiceBlockingStub extends io.grpc.stub.AbstractStub { + private AnotherDynamicServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private AnotherDynamicServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AnotherDynamicServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected AnotherDynamicServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new AnotherDynamicServiceBlockingStub(channel, callOptions); } @@ -197,15 +184,19 @@ public io.grpc.reflection.testing.DynamicReply method(io.grpc.reflection.testing * AnotherDynamicService * */ - public static final class AnotherDynamicServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private AnotherDynamicServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class AnotherDynamicServiceFutureStub extends io.grpc.stub.AbstractStub { + private AnotherDynamicServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private AnotherDynamicServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AnotherDynamicServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected AnotherDynamicServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new AnotherDynamicServiceFutureStub(channel, callOptions); } diff --git a/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java b/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java index a80ac5fefb2..1b5e7c78c89 100644 --- a/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java +++ b/services/src/generated/test/grpc/io/grpc/reflection/testing/DynamicServiceGrpc.java @@ -65,14 +65,7 @@ io.grpc.reflection.testing.DynamicReply> getMethodMethod() { * Creates a new async stub that supports all call types for the service */ public static DynamicServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public DynamicServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new DynamicServiceStub(channel, callOptions); - } - }; - return DynamicServiceStub.newStub(factory, channel); + return new DynamicServiceStub(channel); } /** @@ -80,14 +73,7 @@ public DynamicServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions c */ public static DynamicServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public DynamicServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new DynamicServiceBlockingStub(channel, callOptions); - } - }; - return DynamicServiceBlockingStub.newStub(factory, channel); + return new DynamicServiceBlockingStub(channel); } /** @@ -95,14 +81,7 @@ public DynamicServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallO */ public static DynamicServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public DynamicServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new DynamicServiceFutureStub(channel, callOptions); - } - }; - return DynamicServiceFutureStub.newStub(factory, channel); + return new DynamicServiceFutureStub(channel); } /** @@ -140,15 +119,19 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * A DynamicService * */ - public static final class DynamicServiceStub extends io.grpc.stub.AbstractAsyncStub { - private DynamicServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class DynamicServiceStub extends io.grpc.stub.AbstractStub { + private DynamicServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private DynamicServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected DynamicServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected DynamicServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new DynamicServiceStub(channel, callOptions); } @@ -169,15 +152,19 @@ public void method(io.grpc.reflection.testing.DynamicRequest request, * A DynamicService * */ - public static final class DynamicServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private DynamicServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class DynamicServiceBlockingStub extends io.grpc.stub.AbstractStub { + private DynamicServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private DynamicServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected DynamicServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected DynamicServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new DynamicServiceBlockingStub(channel, callOptions); } @@ -197,15 +184,19 @@ public io.grpc.reflection.testing.DynamicReply method(io.grpc.reflection.testing * A DynamicService * */ - public static final class DynamicServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private DynamicServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class DynamicServiceFutureStub extends io.grpc.stub.AbstractStub { + private DynamicServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private DynamicServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected DynamicServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected DynamicServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new DynamicServiceFutureStub(channel, callOptions); } diff --git a/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java b/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java index ed328240284..f88764670d1 100644 --- a/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java +++ b/services/src/generated/test/grpc/io/grpc/reflection/testing/ReflectableServiceGrpc.java @@ -62,14 +62,7 @@ io.grpc.reflection.testing.Reply> getMethodMethod() { * Creates a new async stub that supports all call types for the service */ public static ReflectableServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReflectableServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReflectableServiceStub(channel, callOptions); - } - }; - return ReflectableServiceStub.newStub(factory, channel); + return new ReflectableServiceStub(channel); } /** @@ -77,14 +70,7 @@ public ReflectableServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptio */ public static ReflectableServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReflectableServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReflectableServiceBlockingStub(channel, callOptions); - } - }; - return ReflectableServiceBlockingStub.newStub(factory, channel); + return new ReflectableServiceBlockingStub(channel); } /** @@ -92,14 +78,7 @@ public ReflectableServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.C */ public static ReflectableServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ReflectableServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ReflectableServiceFutureStub(channel, callOptions); - } - }; - return ReflectableServiceFutureStub.newStub(factory, channel); + return new ReflectableServiceFutureStub(channel); } /** @@ -128,15 +107,19 @@ public void method(io.grpc.reflection.testing.Request request, /** */ - public static final class ReflectableServiceStub extends io.grpc.stub.AbstractAsyncStub { - private ReflectableServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReflectableServiceStub extends io.grpc.stub.AbstractStub { + private ReflectableServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private ReflectableServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReflectableServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReflectableServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReflectableServiceStub(channel, callOptions); } @@ -151,15 +134,19 @@ public void method(io.grpc.reflection.testing.Request request, /** */ - public static final class ReflectableServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ReflectableServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReflectableServiceBlockingStub extends io.grpc.stub.AbstractStub { + private ReflectableServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ReflectableServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReflectableServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReflectableServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReflectableServiceBlockingStub(channel, callOptions); } @@ -173,15 +160,19 @@ public io.grpc.reflection.testing.Reply method(io.grpc.reflection.testing.Reques /** */ - public static final class ReflectableServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private ReflectableServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ReflectableServiceFutureStub extends io.grpc.stub.AbstractStub { + private ReflectableServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ReflectableServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ReflectableServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ReflectableServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ReflectableServiceFutureStub(channel, callOptions); } diff --git a/stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java b/stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java deleted file mode 100644 index 2b12b39921d..00000000000 --- a/stub/src/main/java/io/grpc/stub/AbstractAsyncStub.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.stub.ClientCalls.StubType; -import javax.annotation.CheckReturnValue; -import javax.annotation.concurrent.ThreadSafe; - -/** - * Stub implementations for async stubs. - * - *

    DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder - * to create a real channel suitable for testing. It is also possible to mock Channel instead. - * - * @since 1.25.0 - */ -@ThreadSafe -@CheckReturnValue -public abstract class AbstractAsyncStub> extends AbstractStub { - - protected AbstractAsyncStub(Channel channel, CallOptions callOptions) { - super(channel, callOptions); - } - - /** - * Returns a new async stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create an async stub - * @param channel the channel that this stub will use to do communications - */ - public static > T newStub( - StubFactory factory, Channel channel) { - return newStub(factory, channel, CallOptions.DEFAULT); - } - - /** - * Returns a new async stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create an async stub - * @param channel the channel that this stub will use to do communications - * @param callOptions the runtime call options to be applied to every call on this stub - */ - public static > T newStub( - StubFactory factory, Channel channel, CallOptions callOptions) { - T stub = factory.newStub( - channel, callOptions.withOption(ClientCalls.STUB_TYPE_OPTION, StubType.ASYNC)); - assert stub instanceof AbstractAsyncStub - : String.format("Expected AbstractAsyncStub, but got %s.", stub.getClass()); - return stub; - } -} diff --git a/stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java b/stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java deleted file mode 100644 index 8b13e0d012f..00000000000 --- a/stub/src/main/java/io/grpc/stub/AbstractBlockingStub.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.stub.ClientCalls.StubType; -import javax.annotation.CheckReturnValue; -import javax.annotation.concurrent.ThreadSafe; - -/** - * Stub implementations for blocking stubs. - * - *

    DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder - * to create a real channel suitable for testing. It is also possible to mock Channel instead. - * - * @since 1.25.0 - */ -@ThreadSafe -@CheckReturnValue -public abstract class AbstractBlockingStub> - extends AbstractStub { - - protected AbstractBlockingStub(Channel channel, CallOptions callOptions) { - super(channel, callOptions); - } - - /** - * Returns a new blocking stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create a blocking stub - * @param channel the channel that this stub will use to do communications - */ - public static > T newStub( - StubFactory factory, Channel channel) { - return newStub(factory, channel, CallOptions.DEFAULT); - } - - /** - * Returns a new blocking stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create a blocking stub - * @param channel the channel that this stub will use to do communications - * @param callOptions the runtime call options to be applied to every call on this stub - */ - public static > T newStub( - StubFactory factory, Channel channel, CallOptions callOptions) { - T stub = factory.newStub( - channel, callOptions.withOption(ClientCalls.STUB_TYPE_OPTION, StubType.BLOCKING)); - assert stub instanceof AbstractBlockingStub - : String.format("Expected AbstractBlockingStub, but got %s.", stub.getClass()); - return stub; - } -} diff --git a/stub/src/main/java/io/grpc/stub/AbstractFutureStub.java b/stub/src/main/java/io/grpc/stub/AbstractFutureStub.java deleted file mode 100644 index 86d37eddf0a..00000000000 --- a/stub/src/main/java/io/grpc/stub/AbstractFutureStub.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.stub.ClientCalls.StubType; -import javax.annotation.CheckReturnValue; -import javax.annotation.concurrent.ThreadSafe; - -/** - * Stub implementations for future stubs. - * - *

    DO NOT MOCK: Customizing options doesn't work properly in mocks. Use InProcessChannelBuilder - * to create a real channel suitable for testing. It is also possible to mock Channel instead. - * - * @since 1.25.0 - */ -@ThreadSafe -@CheckReturnValue -public abstract class AbstractFutureStub> extends AbstractStub { - - protected AbstractFutureStub(Channel channel, CallOptions callOptions) { - super(channel, callOptions); - } - - /** - * Returns a new future stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create a future stub - * @param channel the channel that this stub will use to do communications - */ - public static > T newStub( - StubFactory factory, Channel channel) { - return newStub(factory, channel, CallOptions.DEFAULT); - } - - /** - * Returns a new future stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create a future stub - * @param channel the channel that this stub will use to do communications - * @param callOptions the runtime call options to be applied to every call on this stub - * @return a future stub - */ - public static > T newStub( - StubFactory factory, Channel channel, CallOptions callOptions) { - T stub = factory.newStub( - channel, callOptions.withOption(ClientCalls.STUB_TYPE_OPTION, StubType.FUTURE)); - assert stub instanceof AbstractFutureStub - : String.format("Expected AbstractFutureStub, but got %s.", stub.getClass()); - return stub; - } -} diff --git a/stub/src/main/java/io/grpc/stub/AbstractStub.java b/stub/src/main/java/io/grpc/stub/AbstractStub.java index f3a16109dae..346512adc03 100644 --- a/stub/src/main/java/io/grpc/stub/AbstractStub.java +++ b/stub/src/main/java/io/grpc/stub/AbstractStub.java @@ -101,31 +101,6 @@ public final CallOptions getCallOptions() { */ protected abstract S build(Channel channel, CallOptions callOptions); - /** - * Returns a new stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create a stub - * @param channel the channel that this stub will use to do communications - */ - public static > T newStub( - StubFactory factory, Channel channel) { - return newStub(factory, channel, CallOptions.DEFAULT); - } - - /** - * Returns a new stub with the given channel for the provided method configurations. - * - * @since 1.25.0 - * @param factory the factory to create a stub - * @param channel the channel that this stub will use to do communications - * @param callOptions the runtime call options to be applied to every call on this stub - */ - public static > T newStub( - StubFactory factory, Channel channel, CallOptions callOptions) { - return factory.newStub(channel, callOptions); - } - /** * Returns a new stub with an absolute deadline. * @@ -249,13 +224,4 @@ public final S withMaxInboundMessageSize(int maxSize) { public final S withMaxOutboundMessageSize(int maxSize) { return build(channel, callOptions.withMaxOutboundMessageSize(maxSize)); } - - /** - * A factory class for stub. - * - * @since 1.25.0 - */ - public interface StubFactory> { - T newStub(Channel channel, CallOptions callOptions); - } } diff --git a/stub/src/main/java/io/grpc/stub/ClientCalls.java b/stub/src/main/java/io/grpc/stub/ClientCalls.java index 82793cd3d89..7240e122d2a 100644 --- a/stub/src/main/java/io/grpc/stub/ClientCalls.java +++ b/stub/src/main/java/io/grpc/stub/ClientCalls.java @@ -729,14 +729,4 @@ public void execute(Runnable runnable) { LockSupport.unpark(waiter); // no-op if null } } - - enum StubType { - BLOCKING, FUTURE, ASYNC - } - - /** - * Internal {@link CallOptions.Key} to indicate stub types. - */ - static final CallOptions.Key STUB_TYPE_OPTION = - CallOptions.Key.create("internal-stub-type"); } diff --git a/stub/src/main/java/io/grpc/stub/InternalClientCalls.java b/stub/src/main/java/io/grpc/stub/InternalClientCalls.java deleted file mode 100644 index abd7d07585b..00000000000 --- a/stub/src/main/java/io/grpc/stub/InternalClientCalls.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import io.grpc.CallOptions; -import io.grpc.Internal; - -/** - * Internal {@link ClientCalls} accessor. This is intended for usage internal to the gRPC - * team. If you *really* think you need to use this, contact the gRPC team first. - */ -@Internal -public final class InternalClientCalls { - - /** Internal accessor for {@link ClientCalls#STUB_TYPE_OPTION}. */ - public static CallOptions.Key getStubTypeOption() { - return ClientCalls.STUB_TYPE_OPTION; - } - - /** Returns {@link StubType} from call options. */ - public static StubType getStubType(CallOptions callOptions) { - return StubType.of(callOptions.getOption(ClientCalls.STUB_TYPE_OPTION)); - } - - /** Companion enum for internal enum {@link ClientCalls.StubType}. */ - public enum StubType { - BLOCKING(ClientCalls.StubType.BLOCKING), - ASYNC(ClientCalls.StubType.ASYNC), - FUTURE(ClientCalls.StubType.FUTURE); - - private final ClientCalls.StubType internalType; - - StubType(ClientCalls.StubType internalType) { - this.internalType = internalType; - } - - /** Returns companion enum value of passed internal enum equivalent. */ - public static StubType of(ClientCalls.StubType internal) { - for (StubType value : StubType.values()) { - if (value.internalType == internal) { - return value; - } - } - throw new AssertionError("Unknown StubType: " + internal.name()); - } - } -} diff --git a/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java deleted file mode 100644 index 0277b7a66ca..00000000000 --- a/stub/src/test/java/io/grpc/stub/AbstractAsyncStubTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.stub.AbstractAsyncStubTest.NoopAsyncStub; -import io.grpc.stub.AbstractBlockingStubTest.NoopBlockingStub; -import io.grpc.stub.AbstractFutureStubTest.NoopFutureStub; -import io.grpc.stub.AbstractStub.StubFactory; -import io.grpc.stub.ClientCalls.StubType; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class AbstractAsyncStubTest extends BaseAbstractStubTest { - - @Override - NoopAsyncStub create(Channel channel, CallOptions callOptions) { - return new NoopAsyncStub(channel, callOptions); - } - - @Test - public void defaultCallOptions() { - NoopAsyncStub stub = NoopAsyncStub.newStub(new StubFactory() { - @Override - public NoopAsyncStub newStub(Channel channel, CallOptions callOptions) { - return create(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - - assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) - .isEqualTo(StubType.ASYNC); - } - - @Test - @SuppressWarnings("AssertionFailureIgnored") - public void newStub_futureStub_throwsException() { - try { - NoopFutureStub unused = NoopAsyncStub.newStub(new StubFactory() { - @Override - public NoopFutureStub newStub(Channel channel, CallOptions callOptions) { - return new NoopFutureStub(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - fail("should not reach here"); - } catch (AssertionError e) { - assertThat(e).hasMessageThat().startsWith("Expected AbstractAsyncStub"); - } - } - - @Test - @SuppressWarnings("AssertionFailureIgnored") - public void newStub_blockingStub_throwsException() { - try { - NoopBlockingStub unused = NoopAsyncStub.newStub(new StubFactory() { - @Override - public NoopBlockingStub newStub(Channel channel, CallOptions callOptions) { - return new NoopBlockingStub(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - fail("should not reach here"); - } catch (AssertionError e) { - assertThat(e).hasMessageThat().startsWith("Expected AbstractAsyncStub"); - } - } - - static class NoopAsyncStub extends AbstractAsyncStub { - - NoopAsyncStub(Channel channel, CallOptions options) { - super(channel, options); - } - - @Override - protected NoopAsyncStub build(Channel channel, CallOptions callOptions) { - return new NoopAsyncStub(channel, callOptions); - } - } -} diff --git a/stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java deleted file mode 100644 index a3477da2bb5..00000000000 --- a/stub/src/test/java/io/grpc/stub/AbstractBlockingStubTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.stub.AbstractAsyncStubTest.NoopAsyncStub; -import io.grpc.stub.AbstractBlockingStubTest.NoopBlockingStub; -import io.grpc.stub.AbstractFutureStubTest.NoopFutureStub; -import io.grpc.stub.AbstractStub.StubFactory; -import io.grpc.stub.ClientCalls.StubType; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class AbstractBlockingStubTest extends BaseAbstractStubTest { - - @Override - NoopBlockingStub create(Channel channel, CallOptions callOptions) { - return new NoopBlockingStub(channel, callOptions); - } - - @Test - public void defaultCallOptions() { - NoopBlockingStub stub = NoopBlockingStub.newStub(new StubFactory() { - @Override - public NoopBlockingStub newStub(Channel channel, CallOptions callOptions) { - return create(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - - assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) - .isEqualTo(StubType.BLOCKING); - } - - @Test - @SuppressWarnings("AssertionFailureIgnored") - public void newStub_asyncStub_throwsException() { - try { - NoopAsyncStub unused = NoopBlockingStub.newStub(new StubFactory() { - @Override - public NoopAsyncStub newStub(Channel channel, CallOptions callOptions) { - return new NoopAsyncStub(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - fail("should not reach here"); - } catch (AssertionError e) { - assertThat(e).hasMessageThat().startsWith("Expected AbstractBlockingStub"); - } - } - - @Test - @SuppressWarnings("AssertionFailureIgnored") - public void newStub_futureStub_throwsException() { - try { - NoopFutureStub unused = NoopBlockingStub.newStub(new StubFactory() { - @Override - public NoopFutureStub newStub(Channel channel, CallOptions callOptions) { - return new NoopFutureStub(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - fail("should not reach here"); - } catch (AssertionError e) { - assertThat(e).hasMessageThat().startsWith("Expected AbstractBlockingStub"); - } - } - - static class NoopBlockingStub extends AbstractBlockingStub { - - NoopBlockingStub(Channel channel, CallOptions options) { - super(channel, options); - } - - @Override - protected NoopBlockingStub build(Channel channel, CallOptions callOptions) { - return new NoopBlockingStub(channel, callOptions); - } - } -} \ No newline at end of file diff --git a/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java deleted file mode 100644 index 0c0fdaac91f..00000000000 --- a/stub/src/test/java/io/grpc/stub/AbstractFutureStubTest.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2019 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.fail; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.stub.AbstractAsyncStubTest.NoopAsyncStub; -import io.grpc.stub.AbstractBlockingStubTest.NoopBlockingStub; -import io.grpc.stub.AbstractFutureStubTest.NoopFutureStub; -import io.grpc.stub.AbstractStub.StubFactory; -import io.grpc.stub.ClientCalls.StubType; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -@RunWith(JUnit4.class) -public class AbstractFutureStubTest extends BaseAbstractStubTest { - - @Override - NoopFutureStub create(Channel channel, CallOptions callOptions) { - return new NoopFutureStub(channel, callOptions); - } - - @Test - public void defaultCallOptions() { - NoopFutureStub stub = NoopFutureStub.newStub(new StubFactory() { - @Override - public NoopFutureStub newStub(Channel channel, CallOptions callOptions) { - return create(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - - assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) - .isEqualTo(StubType.FUTURE); - } - - @Test - @SuppressWarnings("AssertionFailureIgnored") - public void newStub_asyncStub_throwsException() { - try { - NoopAsyncStub unused = NoopFutureStub.newStub(new StubFactory() { - @Override - public NoopAsyncStub newStub(Channel channel, CallOptions callOptions) { - return new NoopAsyncStub(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - fail("should not reach here"); - } catch (AssertionError e) { - assertThat(e).hasMessageThat().startsWith("Expected AbstractFutureStub"); - } - } - - @Test - @SuppressWarnings("AssertionFailureIgnored") - public void newStub_blockingStub_throwsException() { - try { - NoopBlockingStub unused = NoopFutureStub.newStub(new StubFactory() { - @Override - public NoopBlockingStub newStub(Channel channel, CallOptions callOptions) { - return new NoopBlockingStub(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - fail("should not reach here"); - } catch (AssertionError e) { - assertThat(e).hasMessageThat().startsWith("Expected AbstractFutureStub"); - } - } - - static class NoopFutureStub extends AbstractFutureStub { - - NoopFutureStub(Channel channel, CallOptions options) { - super(channel, options); - } - - @Override - protected NoopFutureStub build(Channel channel, CallOptions callOptions) { - return new NoopFutureStub(channel, callOptions); - } - } -} \ No newline at end of file diff --git a/stub/src/test/java/io/grpc/stub/AbstractStubTest.java b/stub/src/test/java/io/grpc/stub/AbstractStubTest.java index 9006b8679e4..7c73f69d18d 100644 --- a/stub/src/test/java/io/grpc/stub/AbstractStubTest.java +++ b/stub/src/test/java/io/grpc/stub/AbstractStubTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 The gRPC Authors + * Copyright 2016 The gRPC Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,39 +16,65 @@ package io.grpc.stub; -import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import io.grpc.CallOptions; import io.grpc.Channel; -import io.grpc.stub.AbstractStub.StubFactory; -import io.grpc.stub.AbstractStubTest.NoopStub; +import java.util.concurrent.Executor; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @RunWith(JUnit4.class) -public class AbstractStubTest extends BaseAbstractStubTest { +public class AbstractStubTest { - @Override - NoopStub create(Channel channel, CallOptions callOptions) { - return new NoopStub(channel, callOptions); + @Mock + Channel channel; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); } - @Test - public void defaultCallOptions() { - NoopStub stub = NoopStub.newStub(new StubFactory() { - @Override - public NoopStub newStub(Channel channel, CallOptions callOptions) { - return create(channel, callOptions); - } - }, channel, CallOptions.DEFAULT); - - assertThat(stub.getCallOptions().getOption(ClientCalls.STUB_TYPE_OPTION)) - .isNull(); + @Test(expected = NullPointerException.class) + public void channelMustNotBeNull() { + new NoopStub(null); + } + + @Test(expected = NullPointerException.class) + public void callOptionsMustNotBeNull() { + new NoopStub(channel, null); + } + + @Test(expected = NullPointerException.class) + public void channelMustNotBeNull2() { + new NoopStub(null, CallOptions.DEFAULT); + } + + @Test() + public void withWaitForReady() { + NoopStub stub = new NoopStub(channel); + CallOptions callOptions = stub.getCallOptions(); + assertFalse(callOptions.isWaitForReady()); + + stub = stub.withWaitForReady(); + callOptions = stub.getCallOptions(); + assertTrue(callOptions.isWaitForReady()); } class NoopStub extends AbstractStub { + NoopStub(Channel channel) { + super(channel); + } + NoopStub(Channel channel, CallOptions options) { super(channel, options); } @@ -58,5 +84,18 @@ protected NoopStub build(Channel channel, CallOptions callOptions) { return new NoopStub(channel, callOptions); } } -} + @Test + public void withExecutor() { + NoopStub stub = new NoopStub(channel); + CallOptions callOptions = stub.getCallOptions(); + + assertNull(callOptions.getExecutor()); + + Executor executor = mock(Executor.class); + stub = stub.withExecutor(executor); + callOptions = stub.getCallOptions(); + + assertEquals(callOptions.getExecutor(), executor); + } +} diff --git a/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java b/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java deleted file mode 100644 index b197c78aca2..00000000000 --- a/stub/src/test/java/io/grpc/stub/BaseAbstractStubTest.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2016 The gRPC Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.grpc.stub; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; - -import io.grpc.CallOptions; -import io.grpc.Channel; -import java.util.concurrent.Executor; -import javax.annotation.Nullable; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -/** Standard unit tests for AbstractStub and its subclasses. */ -abstract class BaseAbstractStubTest> { - - @Mock - Channel channel; - - @Before - public void setup() { - MockitoAnnotations.initMocks(this); - } - - T create(Channel channel) { - return create(channel, CallOptions.DEFAULT); - } - - abstract T create(@Nullable Channel channel, @Nullable CallOptions callOptions); - - @Test - public void callOptionsMustNotBeNull() { - try { - create(channel, null); - fail("NullPointerException expected"); - } catch (NullPointerException npe) { - // expected - } - } - - @Test - public void channelMustNotBeNull2() { - try { - create(null, CallOptions.DEFAULT); - fail("NullPointerException expected"); - } catch (NullPointerException npe) { - // expected - } - } - - @Test - public void withWaitForReady() { - T stub = create(channel); - CallOptions callOptions = stub.getCallOptions(); - assertFalse(callOptions.isWaitForReady()); - - stub = stub.withWaitForReady(); - callOptions = stub.getCallOptions(); - assertTrue(callOptions.isWaitForReady()); - } - - @Test - public void withExecutor() { - T stub = create(channel); - CallOptions callOptions = stub.getCallOptions(); - - assertNull(callOptions.getExecutor()); - - Executor executor = mock(Executor.class); - stub = stub.withExecutor(executor); - callOptions = stub.getCallOptions(); - - assertEquals(callOptions.getExecutor(), executor); - } -} diff --git a/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java b/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java index fad64947a58..f976e7587f3 100644 --- a/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java +++ b/testing-proto/src/generated/main/grpc/io/grpc/testing/protobuf/SimpleServiceGrpc.java @@ -158,14 +158,7 @@ io.grpc.testing.protobuf.SimpleResponse> getBidiStreamingRpcMethod() { * Creates a new async stub that supports all call types for the service */ public static SimpleServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public SimpleServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new SimpleServiceStub(channel, callOptions); - } - }; - return SimpleServiceStub.newStub(factory, channel); + return new SimpleServiceStub(channel); } /** @@ -173,14 +166,7 @@ public SimpleServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions ca */ public static SimpleServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public SimpleServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new SimpleServiceBlockingStub(channel, callOptions); - } - }; - return SimpleServiceBlockingStub.newStub(factory, channel); + return new SimpleServiceBlockingStub(channel); } /** @@ -188,14 +174,7 @@ public SimpleServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOp */ public static SimpleServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public SimpleServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new SimpleServiceFutureStub(channel, callOptions); - } - }; - return SimpleServiceFutureStub.newStub(factory, channel); + return new SimpleServiceFutureStub(channel); } /** @@ -284,15 +263,19 @@ public io.grpc.stub.StreamObserver bidiS * A simple service for test. * */ - public static final class SimpleServiceStub extends io.grpc.stub.AbstractAsyncStub { - private SimpleServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class SimpleServiceStub extends io.grpc.stub.AbstractStub { + private SimpleServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private SimpleServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected SimpleServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected SimpleServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new SimpleServiceStub(channel, callOptions); } @@ -346,15 +329,19 @@ public io.grpc.stub.StreamObserver bidiS * A simple service for test. * */ - public static final class SimpleServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private SimpleServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class SimpleServiceBlockingStub extends io.grpc.stub.AbstractStub { + private SimpleServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private SimpleServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected SimpleServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected SimpleServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new SimpleServiceBlockingStub(channel, callOptions); } @@ -385,15 +372,19 @@ public java.util.Iterator serverStreami * A simple service for test. * */ - public static final class SimpleServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private SimpleServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class SimpleServiceFutureStub extends io.grpc.stub.AbstractStub { + private SimpleServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private SimpleServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected SimpleServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected SimpleServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new SimpleServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java b/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java index 59e43de5f93..500543def62 100644 --- a/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java +++ b/xds/src/generated/main/grpc/com/github/udpa/udpa/service/orca/v1/OpenRcaServiceGrpc.java @@ -72,14 +72,7 @@ com.github.udpa.udpa.data.orca.v1.OrcaLoadReport> getStreamCoreMetricsMethod() { * Creates a new async stub that supports all call types for the service */ public static OpenRcaServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public OpenRcaServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new OpenRcaServiceStub(channel, callOptions); - } - }; - return OpenRcaServiceStub.newStub(factory, channel); + return new OpenRcaServiceStub(channel); } /** @@ -87,14 +80,7 @@ public OpenRcaServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions c */ public static OpenRcaServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public OpenRcaServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new OpenRcaServiceBlockingStub(channel, callOptions); - } - }; - return OpenRcaServiceBlockingStub.newStub(factory, channel); + return new OpenRcaServiceBlockingStub(channel); } /** @@ -102,14 +88,7 @@ public OpenRcaServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallO */ public static OpenRcaServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public OpenRcaServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new OpenRcaServiceFutureStub(channel, callOptions); - } - }; - return OpenRcaServiceFutureStub.newStub(factory, channel); + return new OpenRcaServiceFutureStub(channel); } /** @@ -158,15 +137,19 @@ public void streamCoreMetrics(com.github.udpa.udpa.service.orca.v1.OrcaLoadRepor * a new call to change backend reporting frequency. * */ - public static final class OpenRcaServiceStub extends io.grpc.stub.AbstractAsyncStub { - private OpenRcaServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class OpenRcaServiceStub extends io.grpc.stub.AbstractStub { + private OpenRcaServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private OpenRcaServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected OpenRcaServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected OpenRcaServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new OpenRcaServiceStub(channel, callOptions); } @@ -191,15 +174,19 @@ public void streamCoreMetrics(com.github.udpa.udpa.service.orca.v1.OrcaLoadRepor * a new call to change backend reporting frequency. * */ - public static final class OpenRcaServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private OpenRcaServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class OpenRcaServiceBlockingStub extends io.grpc.stub.AbstractStub { + private OpenRcaServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private OpenRcaServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected OpenRcaServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected OpenRcaServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new OpenRcaServiceBlockingStub(channel, callOptions); } @@ -224,15 +211,19 @@ public java.util.Iterator stre * a new call to change backend reporting frequency. * */ - public static final class OpenRcaServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private OpenRcaServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class OpenRcaServiceFutureStub extends io.grpc.stub.AbstractStub { + private OpenRcaServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private OpenRcaServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected OpenRcaServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected OpenRcaServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new OpenRcaServiceFutureStub(channel, callOptions); } } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java index d812191e7da..e476e83c0ed 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ClusterDiscoveryServiceGrpc.java @@ -127,14 +127,7 @@ io.envoyproxy.envoy.api.v2.DiscoveryResponse> getFetchClustersMethod() { * Creates a new async stub that supports all call types for the service */ public static ClusterDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ClusterDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ClusterDiscoveryServiceStub(channel, callOptions); - } - }; - return ClusterDiscoveryServiceStub.newStub(factory, channel); + return new ClusterDiscoveryServiceStub(channel); } /** @@ -142,14 +135,7 @@ public ClusterDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.Call */ public static ClusterDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ClusterDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ClusterDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return ClusterDiscoveryServiceBlockingStub.newStub(factory, channel); + return new ClusterDiscoveryServiceBlockingStub(channel); } /** @@ -157,14 +143,7 @@ public ClusterDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.g */ public static ClusterDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ClusterDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ClusterDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return ClusterDiscoveryServiceFutureStub.newStub(factory, channel); + return new ClusterDiscoveryServiceFutureStub(channel); } /** @@ -227,15 +206,19 @@ public void fetchClusters(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, * Return list of all clusters this proxy will load balance to. * */ - public static final class ClusterDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private ClusterDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ClusterDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private ClusterDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private ClusterDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ClusterDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ClusterDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ClusterDiscoveryServiceStub(channel, callOptions); } @@ -269,15 +252,19 @@ public void fetchClusters(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, * Return list of all clusters this proxy will load balance to. * */ - public static final class ClusterDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ClusterDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ClusterDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private ClusterDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ClusterDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ClusterDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ClusterDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ClusterDiscoveryServiceBlockingStub(channel, callOptions); } @@ -294,15 +281,19 @@ public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchClusters(io.envoyproxy. * Return list of all clusters this proxy will load balance to. * */ - public static final class ClusterDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private ClusterDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ClusterDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private ClusterDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ClusterDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ClusterDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ClusterDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ClusterDiscoveryServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java index ce576e0ccb1..2726b2bf3ad 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/EndpointDiscoveryServiceGrpc.java @@ -124,14 +124,7 @@ io.envoyproxy.envoy.api.v2.DiscoveryResponse> getFetchEndpointsMethod() { * Creates a new async stub that supports all call types for the service */ public static EndpointDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public EndpointDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new EndpointDiscoveryServiceStub(channel, callOptions); - } - }; - return EndpointDiscoveryServiceStub.newStub(factory, channel); + return new EndpointDiscoveryServiceStub(channel); } /** @@ -139,14 +132,7 @@ public EndpointDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.Cal */ public static EndpointDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public EndpointDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new EndpointDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return EndpointDiscoveryServiceBlockingStub.newStub(factory, channel); + return new EndpointDiscoveryServiceBlockingStub(channel); } /** @@ -154,14 +140,7 @@ public EndpointDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io. */ public static EndpointDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public EndpointDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new EndpointDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return EndpointDiscoveryServiceFutureStub.newStub(factory, channel); + return new EndpointDiscoveryServiceFutureStub(channel); } /** @@ -222,15 +201,19 @@ public void fetchEndpoints(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, /** */ - public static final class EndpointDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private EndpointDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class EndpointDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private EndpointDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private EndpointDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected EndpointDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected EndpointDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new EndpointDiscoveryServiceStub(channel, callOptions); } @@ -265,15 +248,19 @@ public void fetchEndpoints(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, /** */ - public static final class EndpointDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private EndpointDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class EndpointDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private EndpointDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private EndpointDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected EndpointDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected EndpointDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new EndpointDiscoveryServiceBlockingStub(channel, callOptions); } @@ -287,15 +274,19 @@ public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchEndpoints(io.envoyproxy /** */ - public static final class EndpointDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private EndpointDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class EndpointDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private EndpointDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private EndpointDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected EndpointDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected EndpointDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new EndpointDiscoveryServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java index f772eb15e48..36047625d0e 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ListenerDiscoveryServiceGrpc.java @@ -130,14 +130,7 @@ io.envoyproxy.envoy.api.v2.DiscoveryResponse> getFetchListenersMethod() { * Creates a new async stub that supports all call types for the service */ public static ListenerDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ListenerDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ListenerDiscoveryServiceStub(channel, callOptions); - } - }; - return ListenerDiscoveryServiceStub.newStub(factory, channel); + return new ListenerDiscoveryServiceStub(channel); } /** @@ -145,14 +138,7 @@ public ListenerDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.Cal */ public static ListenerDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ListenerDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ListenerDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return ListenerDiscoveryServiceBlockingStub.newStub(factory, channel); + return new ListenerDiscoveryServiceBlockingStub(channel); } /** @@ -160,14 +146,7 @@ public ListenerDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io. */ public static ListenerDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ListenerDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ListenerDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return ListenerDiscoveryServiceFutureStub.newStub(factory, channel); + return new ListenerDiscoveryServiceFutureStub(channel); } /** @@ -236,15 +215,19 @@ public void fetchListeners(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, * allowed to drain from listeners that are no longer present. * */ - public static final class ListenerDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private ListenerDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ListenerDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private ListenerDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private ListenerDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ListenerDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ListenerDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ListenerDiscoveryServiceStub(channel, callOptions); } @@ -281,15 +264,19 @@ public void fetchListeners(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, * allowed to drain from listeners that are no longer present. * */ - public static final class ListenerDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ListenerDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ListenerDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private ListenerDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ListenerDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ListenerDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ListenerDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ListenerDiscoveryServiceBlockingStub(channel, callOptions); } @@ -309,15 +296,19 @@ public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchListeners(io.envoyproxy * allowed to drain from listeners that are no longer present. * */ - public static final class ListenerDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private ListenerDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ListenerDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private ListenerDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ListenerDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ListenerDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ListenerDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ListenerDiscoveryServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java index f22418224dc..9511c915f3c 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/RouteDiscoveryServiceGrpc.java @@ -131,14 +131,7 @@ io.envoyproxy.envoy.api.v2.DiscoveryResponse> getFetchRoutesMethod() { * Creates a new async stub that supports all call types for the service */ public static RouteDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public RouteDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new RouteDiscoveryServiceStub(channel, callOptions); - } - }; - return RouteDiscoveryServiceStub.newStub(factory, channel); + return new RouteDiscoveryServiceStub(channel); } /** @@ -146,14 +139,7 @@ public RouteDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOp */ public static RouteDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public RouteDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new RouteDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return RouteDiscoveryServiceBlockingStub.newStub(factory, channel); + return new RouteDiscoveryServiceBlockingStub(channel); } /** @@ -161,14 +147,7 @@ public RouteDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grp */ public static RouteDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public RouteDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new RouteDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return RouteDiscoveryServiceFutureStub.newStub(factory, channel); + return new RouteDiscoveryServiceFutureStub(channel); } /** @@ -239,15 +218,19 @@ public void fetchRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, * a route table via this identifier. * */ - public static final class RouteDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private RouteDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class RouteDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private RouteDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private RouteDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected RouteDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected RouteDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new RouteDiscoveryServiceStub(channel, callOptions); } @@ -285,15 +268,19 @@ public void fetchRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest request, * a route table via this identifier. * */ - public static final class RouteDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private RouteDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class RouteDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private RouteDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private RouteDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected RouteDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected RouteDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new RouteDiscoveryServiceBlockingStub(channel, callOptions); } @@ -314,15 +301,19 @@ public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchRoutes(io.envoyproxy.en * a route table via this identifier. * */ - public static final class RouteDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private RouteDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class RouteDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private RouteDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private RouteDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected RouteDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected RouteDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new RouteDiscoveryServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java index c19809f816e..7943cf470d0 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/ScopedRoutesDiscoveryServiceGrpc.java @@ -135,14 +135,7 @@ io.envoyproxy.envoy.api.v2.DiscoveryResponse> getFetchScopedRoutesMethod() { * Creates a new async stub that supports all call types for the service */ public static ScopedRoutesDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ScopedRoutesDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ScopedRoutesDiscoveryServiceStub(channel, callOptions); - } - }; - return ScopedRoutesDiscoveryServiceStub.newStub(factory, channel); + return new ScopedRoutesDiscoveryServiceStub(channel); } /** @@ -150,14 +143,7 @@ public ScopedRoutesDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc */ public static ScopedRoutesDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ScopedRoutesDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ScopedRoutesDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return ScopedRoutesDiscoveryServiceBlockingStub.newStub(factory, channel); + return new ScopedRoutesDiscoveryServiceBlockingStub(channel); } /** @@ -165,14 +151,7 @@ public ScopedRoutesDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, */ public static ScopedRoutesDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public ScopedRoutesDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new ScopedRoutesDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return ScopedRoutesDiscoveryServiceFutureStub.newStub(factory, channel); + return new ScopedRoutesDiscoveryServiceFutureStub(channel); } /** @@ -251,15 +230,19 @@ public void fetchScopedRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest reques * HTTP request. * */ - public static final class ScopedRoutesDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private ScopedRoutesDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ScopedRoutesDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private ScopedRoutesDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private ScopedRoutesDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ScopedRoutesDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ScopedRoutesDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ScopedRoutesDiscoveryServiceStub(channel, callOptions); } @@ -301,15 +284,19 @@ public void fetchScopedRoutes(io.envoyproxy.envoy.api.v2.DiscoveryRequest reques * HTTP request. * */ - public static final class ScopedRoutesDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private ScopedRoutesDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ScopedRoutesDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private ScopedRoutesDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private ScopedRoutesDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ScopedRoutesDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ScopedRoutesDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ScopedRoutesDiscoveryServiceBlockingStub(channel, callOptions); } @@ -334,15 +321,19 @@ public io.envoyproxy.envoy.api.v2.DiscoveryResponse fetchScopedRoutes(io.envoypr * HTTP request. * */ - public static final class ScopedRoutesDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private ScopedRoutesDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class ScopedRoutesDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private ScopedRoutesDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private ScopedRoutesDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected ScopedRoutesDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected ScopedRoutesDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new ScopedRoutesDiscoveryServiceFutureStub(channel, callOptions); } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java index dac821b715e..a60c97e6745 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/api/v2/VirtualHostDiscoveryServiceGrpc.java @@ -74,14 +74,7 @@ io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse> getDeltaVirtualHostsMethod() * Creates a new async stub that supports all call types for the service */ public static VirtualHostDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public VirtualHostDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new VirtualHostDiscoveryServiceStub(channel, callOptions); - } - }; - return VirtualHostDiscoveryServiceStub.newStub(factory, channel); + return new VirtualHostDiscoveryServiceStub(channel); } /** @@ -89,14 +82,7 @@ public VirtualHostDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc. */ public static VirtualHostDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public VirtualHostDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new VirtualHostDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return VirtualHostDiscoveryServiceBlockingStub.newStub(factory, channel); + return new VirtualHostDiscoveryServiceBlockingStub(channel); } /** @@ -104,14 +90,7 @@ public VirtualHostDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, */ public static VirtualHostDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public VirtualHostDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new VirtualHostDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return VirtualHostDiscoveryServiceFutureStub.newStub(factory, channel); + return new VirtualHostDiscoveryServiceFutureStub(channel); } /** @@ -164,15 +143,19 @@ public io.grpc.stub.StreamObserver */ - public static final class VirtualHostDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private VirtualHostDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class VirtualHostDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private VirtualHostDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private VirtualHostDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected VirtualHostDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected VirtualHostDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new VirtualHostDiscoveryServiceStub(channel, callOptions); } @@ -199,15 +182,19 @@ public io.grpc.stub.StreamObserver */ - public static final class VirtualHostDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private VirtualHostDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class VirtualHostDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private VirtualHostDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private VirtualHostDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected VirtualHostDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected VirtualHostDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new VirtualHostDiscoveryServiceBlockingStub(channel, callOptions); } } @@ -226,15 +213,19 @@ protected VirtualHostDiscoveryServiceBlockingStub build( * from the routing table associated with the RouteConfiguration. * */ - public static final class VirtualHostDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private VirtualHostDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class VirtualHostDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private VirtualHostDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private VirtualHostDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected VirtualHostDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected VirtualHostDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new VirtualHostDiscoveryServiceFutureStub(channel, callOptions); } } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java index c9f8eb1ed02..65a23fff755 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/discovery/v2/AggregatedDiscoveryServiceGrpc.java @@ -101,14 +101,7 @@ io.envoyproxy.envoy.api.v2.DeltaDiscoveryResponse> getDeltaAggregatedResourcesMe * Creates a new async stub that supports all call types for the service */ public static AggregatedDiscoveryServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public AggregatedDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new AggregatedDiscoveryServiceStub(channel, callOptions); - } - }; - return AggregatedDiscoveryServiceStub.newStub(factory, channel); + return new AggregatedDiscoveryServiceStub(channel); } /** @@ -116,14 +109,7 @@ public AggregatedDiscoveryServiceStub newStub(io.grpc.Channel channel, io.grpc.C */ public static AggregatedDiscoveryServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public AggregatedDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new AggregatedDiscoveryServiceBlockingStub(channel, callOptions); - } - }; - return AggregatedDiscoveryServiceBlockingStub.newStub(factory, channel); + return new AggregatedDiscoveryServiceBlockingStub(channel); } /** @@ -131,14 +117,7 @@ public AggregatedDiscoveryServiceBlockingStub newStub(io.grpc.Channel channel, i */ public static AggregatedDiscoveryServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public AggregatedDiscoveryServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new AggregatedDiscoveryServiceFutureStub(channel, callOptions); - } - }; - return AggregatedDiscoveryServiceFutureStub.newStub(factory, channel); + return new AggregatedDiscoveryServiceFutureStub(channel); } /** @@ -200,15 +179,19 @@ public io.grpc.stub.StreamObserver */ - public static final class AggregatedDiscoveryServiceStub extends io.grpc.stub.AbstractAsyncStub { - private AggregatedDiscoveryServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class AggregatedDiscoveryServiceStub extends io.grpc.stub.AbstractStub { + private AggregatedDiscoveryServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private AggregatedDiscoveryServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AggregatedDiscoveryServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected AggregatedDiscoveryServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new AggregatedDiscoveryServiceStub(channel, callOptions); } @@ -242,15 +225,19 @@ public io.grpc.stub.StreamObserver */ - public static final class AggregatedDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractBlockingStub { - private AggregatedDiscoveryServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class AggregatedDiscoveryServiceBlockingStub extends io.grpc.stub.AbstractStub { + private AggregatedDiscoveryServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private AggregatedDiscoveryServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AggregatedDiscoveryServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected AggregatedDiscoveryServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new AggregatedDiscoveryServiceBlockingStub(channel, callOptions); } } @@ -265,15 +252,19 @@ protected AggregatedDiscoveryServiceBlockingStub build( * the multiplexed singleton APIs at the Envoy instance and management server. * */ - public static final class AggregatedDiscoveryServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private AggregatedDiscoveryServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class AggregatedDiscoveryServiceFutureStub extends io.grpc.stub.AbstractStub { + private AggregatedDiscoveryServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private AggregatedDiscoveryServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected AggregatedDiscoveryServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected AggregatedDiscoveryServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new AggregatedDiscoveryServiceFutureStub(channel, callOptions); } } diff --git a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java index 66271d2e60c..f00828aa3f5 100644 --- a/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java +++ b/xds/src/generated/main/grpc/io/envoyproxy/envoy/service/load_stats/v2/LoadReportingServiceGrpc.java @@ -62,14 +62,7 @@ io.envoyproxy.envoy.service.load_stats.v2.LoadStatsResponse> getStreamLoadStatsM * Creates a new async stub that supports all call types for the service */ public static LoadReportingServiceStub newStub(io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LoadReportingServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LoadReportingServiceStub(channel, callOptions); - } - }; - return LoadReportingServiceStub.newStub(factory, channel); + return new LoadReportingServiceStub(channel); } /** @@ -77,14 +70,7 @@ public LoadReportingServiceStub newStub(io.grpc.Channel channel, io.grpc.CallOpt */ public static LoadReportingServiceBlockingStub newBlockingStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LoadReportingServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LoadReportingServiceBlockingStub(channel, callOptions); - } - }; - return LoadReportingServiceBlockingStub.newStub(factory, channel); + return new LoadReportingServiceBlockingStub(channel); } /** @@ -92,14 +78,7 @@ public LoadReportingServiceBlockingStub newStub(io.grpc.Channel channel, io.grpc */ public static LoadReportingServiceFutureStub newFutureStub( io.grpc.Channel channel) { - io.grpc.stub.AbstractStub.StubFactory factory = - new io.grpc.stub.AbstractStub.StubFactory() { - @java.lang.Override - public LoadReportingServiceFutureStub newStub(io.grpc.Channel channel, io.grpc.CallOptions callOptions) { - return new LoadReportingServiceFutureStub(channel, callOptions); - } - }; - return LoadReportingServiceFutureStub.newStub(factory, channel); + return new LoadReportingServiceFutureStub(channel); } /** @@ -157,15 +136,19 @@ public io.grpc.stub.StreamObserver { - private LoadReportingServiceStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class LoadReportingServiceStub extends io.grpc.stub.AbstractStub { + private LoadReportingServiceStub(io.grpc.Channel channel) { + super(channel); + } + + private LoadReportingServiceStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadReportingServiceStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected LoadReportingServiceStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new LoadReportingServiceStub(channel, callOptions); } @@ -209,30 +192,38 @@ public io.grpc.stub.StreamObserver { - private LoadReportingServiceBlockingStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class LoadReportingServiceBlockingStub extends io.grpc.stub.AbstractStub { + private LoadReportingServiceBlockingStub(io.grpc.Channel channel) { + super(channel); + } + + private LoadReportingServiceBlockingStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadReportingServiceBlockingStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected LoadReportingServiceBlockingStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new LoadReportingServiceBlockingStub(channel, callOptions); } } /** */ - public static final class LoadReportingServiceFutureStub extends io.grpc.stub.AbstractFutureStub { - private LoadReportingServiceFutureStub( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + public static final class LoadReportingServiceFutureStub extends io.grpc.stub.AbstractStub { + private LoadReportingServiceFutureStub(io.grpc.Channel channel) { + super(channel); + } + + private LoadReportingServiceFutureStub(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { super(channel, callOptions); } @java.lang.Override - protected LoadReportingServiceFutureStub build( - io.grpc.Channel channel, io.grpc.CallOptions callOptions) { + protected LoadReportingServiceFutureStub build(io.grpc.Channel channel, + io.grpc.CallOptions callOptions) { return new LoadReportingServiceFutureStub(channel, callOptions); } } From d1411b205c93034e722bbb46c6e0e323e2ecf701 Mon Sep 17 00:00:00 2001 From: Steve Rao Date: Wed, 23 Oct 2019 06:45:42 +0800 Subject: [PATCH 120/131] examples: adjust comment (#6314) --- .../main/java/io/grpc/examples/advanced/HelloJsonClient.java | 5 +++-- .../examples/experimental/CompressingHelloWorldClient.java | 5 +++-- .../java/io/grpc/examples/header/CustomHeaderClient.java | 5 +++-- .../java/io/grpc/examples/helloworld/HelloWorldClient.java | 5 +++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java b/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java index 9e7d5971f08..264fe76b7d3 100644 --- a/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java +++ b/examples/src/main/java/io/grpc/examples/advanced/HelloJsonClient.java @@ -78,12 +78,13 @@ public void greet(String name) { * greeting. */ public static void main(String[] args) throws Exception { + // Access a service running on the local machine on port 50051 HelloJsonClient client = new HelloJsonClient("localhost", 50051); try { - /* Access a service running on the local machine on port 50051 */ String user = "world"; + // Use the arg as the name to greet if provided if (args.length > 0) { - user = args[0]; /* Use the arg as the name to greet if provided */ + user = args[0]; } client.greet(user); } finally { diff --git a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java index 2ed51a48c19..410b0c7c14c 100644 --- a/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/experimental/CompressingHelloWorldClient.java @@ -73,12 +73,13 @@ public void greet(String name) { * greeting. */ public static void main(String[] args) throws Exception { + // Access a service running on the local machine on port 50051 CompressingHelloWorldClient client = new CompressingHelloWorldClient("localhost", 50051); try { - /* Access a service running on the local machine on port 50051 */ String user = "world"; + // Use the arg as the name to greet if provided if (args.length > 0) { - user = args[0]; /* Use the arg as the name to greet if provided */ + user = args[0]; } client.greet(user); } finally { diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java index 1095c73e71c..93d106dba9e 100644 --- a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java @@ -75,12 +75,13 @@ private void greet(String name) { * Main start the client from the command line. */ public static void main(String[] args) throws Exception { + // Access a service running on the local machine on port 50051 CustomHeaderClient client = new CustomHeaderClient("localhost", 50051); try { - /* Access a service running on the local machine on port 50051 */ String user = "world"; + // Use the arg as the name to greet if provided if (args.length > 0) { - user = args[0]; /* Use the arg as the name to greet if provided */ + user = args[0]; } client.greet(user); } finally { diff --git a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java index 760f77c3bb1..322c0f25f72 100644 --- a/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java +++ b/examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java @@ -70,12 +70,13 @@ public void greet(String name) { * greeting. */ public static void main(String[] args) throws Exception { + // Access a service running on the local machine on port 50051 HelloWorldClient client = new HelloWorldClient("localhost", 50051); try { - /* Access a service running on the local machine on port 50051 */ String user = "world"; + // Use the arg as the name to greet if provided if (args.length > 0) { - user = args[0]; /* Use the arg as the name to greet if provided */ + user = args[0]; } client.greet(user); } finally { From b009e9215671ba5a7caf3ed0298889bccbb9693b Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Tue, 22 Oct 2019 16:55:39 -0700 Subject: [PATCH 121/131] xds: Bump perfmark to 0.19.0 Resolves #6217 --- build.gradle | 4 ++-- examples/pom.xml | 5 +++++ grpclb/build.gradle | 2 ++ repositories.bzl | 4 ++-- services/build.gradle | 2 ++ xds/build.gradle | 2 ++ 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 146487635b9..2dc5a4a347c 100644 --- a/build.gradle +++ b/build.gradle @@ -118,7 +118,7 @@ subprojects { libraries = [ android_annotations: "com.google.android:annotations:4.1.1.4", animalsniffer_annotations: "org.codehaus.mojo:animal-sniffer-annotations:1.17", - errorprone: "com.google.errorprone:error_prone_annotations:2.3.2", + errorprone: "com.google.errorprone:error_prone_annotations:2.3.3", gson: "com.google.code.gson:gson:2.8.5", guava: "com.google.guava:guava:${guavaVersion}", hpack: 'com.twitter:hpack:0.10.1', @@ -134,7 +134,7 @@ subprojects { opencensus_impl: "io.opencensus:opencensus-impl:${opencensusVersion}", opencensus_impl_lite: "io.opencensus:opencensus-impl-lite:${opencensusVersion}", instrumentation_api: 'com.google.instrumentation:instrumentation-api:0.4.3', - perfmark: 'io.perfmark:perfmark-api:0.17.0', + perfmark: 'io.perfmark:perfmark-api:0.19.0', pgv: 'io.envoyproxy.protoc-gen-validate:pgv-java-stub:0.2.0', protobuf: "com.google.protobuf:protobuf-java:${protobufVersion}", protobuf_lite: "com.google.protobuf:protobuf-lite:3.0.1", diff --git a/examples/pom.xml b/examples/pom.xml index feb3748d817..ea29e0f38e7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -62,6 +62,11 @@ protobuf-java-util ${protobuf.version} + + com.google.errorprone + error_prone_annotations + 2.3.3 + junit junit diff --git a/grpclb/build.gradle b/grpclb/build.gradle index bf5a9ca906c..aba171f2c91 100644 --- a/grpclb/build.gradle +++ b/grpclb/build.gradle @@ -18,6 +18,8 @@ dependencies { compile (libraries.protobuf_util) { // prefer 26.0-android from libraries instead of 20.0 exclude group: 'com.google.guava', module: 'guava' + // prefer 2.3.3 from libraries instead of 2.3.2 + exclude group: 'com.google.errorprone', module: 'error_prone_annotations' } compileOnly libraries.javax_annotation testCompile libraries.truth, diff --git a/repositories.bzl b/repositories.bzl index 57d71f11296..d3f3070d9f1 100644 --- a/repositories.bzl +++ b/repositories.bzl @@ -436,9 +436,9 @@ def io_opencensus_grpc_metrics(): def io_perfmark(): jvm_maven_import_external( name = "io_perfmark_perfmark_api", - artifact = "io.perfmark:perfmark-api:0.17.0", + artifact = "io.perfmark:perfmark-api:0.19.0", server_urls = ["http://central.maven.org/maven2"], - artifact_sha256 = "816c11409b8a0c6c9ce1cda14bed526e7b4da0e772da67c5b7b88eefd41520f9", + artifact_sha256 = "b734ba2149712409a44eabdb799f64768578fee0defe1418bb108fe32ea43e1a", licenses = ["notice"], # Apache 2.0 ) diff --git a/services/build.gradle b/services/build.gradle index 2907c7007d6..fc38bc91baa 100644 --- a/services/build.gradle +++ b/services/build.gradle @@ -25,6 +25,8 @@ dependencies { compile (libraries.protobuf_util) { // prefer 26.0-android from libraries instead of 20.0 exclude group: 'com.google.guava', module: 'guava' + // prefer 2.3.3 from libraries instead of 2.3.2 + exclude group: 'com.google.errorprone', module: 'error_prone_annotations' } compileOnly libraries.javax_annotation diff --git a/xds/build.gradle b/xds/build.gradle index f4d452869f3..7f51d6e4da7 100644 --- a/xds/build.gradle +++ b/xds/build.gradle @@ -32,6 +32,8 @@ dependencies { compile (libraries.protobuf_util) { // prefer 26.0-android from libraries instead of 20.0 exclude group: 'com.google.guava', module: 'guava' + // prefer 2.3.3 from libraries instead of 2.3.2 + exclude group: 'com.google.errorprone', module: 'error_prone_annotations' } testCompile project(':grpc-core').sourceSets.test.output From 38952b0b3855419e660bc3a0019a6b209a705e5c Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Wed, 23 Oct 2019 12:05:24 -0700 Subject: [PATCH 122/131] grpclb: cancel stream instead of halfClose when balancer shutdown Previously, if the remote balancer doesn't close the stream after receiving the half-close, the OOB channel will hang there forever. It's safer to always cancel on the client-side so that the OOB channel can be cleaned up timely, regardless of what the remote balancer does. --- grpclb/src/main/java/io/grpc/grpclb/GrpclbState.java | 10 +++------- .../java/io/grpc/grpclb/GrpclbLoadBalancerTest.java | 6 +++++- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/grpclb/src/main/java/io/grpc/grpclb/GrpclbState.java b/grpclb/src/main/java/io/grpc/grpclb/GrpclbState.java index 7c024843773..98bbaa9d415 100644 --- a/grpclb/src/main/java/io/grpc/grpclb/GrpclbState.java +++ b/grpclb/src/main/java/io/grpc/grpclb/GrpclbState.java @@ -279,7 +279,7 @@ private void shutdownLbComm() { private void shutdownLbRpc() { if (lbStream != null) { - lbStream.close(null); + lbStream.close(Status.CANCELLED.withDescription("balancer shutdown").asException()); // lbStream will be set to null in LbStream.cleanup() } } @@ -668,17 +668,13 @@ private void handleStreamClosed(Status error) { helper.refreshNameResolution(); } - void close(@Nullable Exception error) { + void close(Exception error) { if (closed) { return; } closed = true; cleanUp(); - if (error == null) { - lbRequestWriter.onCompleted(); - } else { - lbRequestWriter.onError(error); - } + lbRequestWriter.onError(error); } private void cleanUp() { diff --git a/grpclb/src/test/java/io/grpc/grpclb/GrpclbLoadBalancerTest.java b/grpclb/src/test/java/io/grpc/grpclb/GrpclbLoadBalancerTest.java index 4f01c89cfdc..3d820c52a2a 100644 --- a/grpclb/src/test/java/io/grpc/grpclb/GrpclbLoadBalancerTest.java +++ b/grpclb/src/test/java/io/grpc/grpclb/GrpclbLoadBalancerTest.java @@ -65,6 +65,7 @@ import io.grpc.ManagedChannel; import io.grpc.Metadata; import io.grpc.Status; +import io.grpc.Status.Code; import io.grpc.SynchronizationContext; import io.grpc.grpclb.GrpclbState.BackendEntry; import io.grpc.grpclb.GrpclbState.DropEntry; @@ -1835,7 +1836,10 @@ private void subtestShutdownWithoutSubchannel(String childPolicy) throws Excepti verify(requestObserver, never()).onCompleted(); balancer.shutdown(); - verify(requestObserver).onCompleted(); + ArgumentCaptor throwableCaptor = ArgumentCaptor.forClass(Throwable.class); + verify(requestObserver).onError(throwableCaptor.capture()); + assertThat(Status.fromThrowable(throwableCaptor.getValue()).getCode()) + .isEqualTo(Code.CANCELLED); } @SuppressWarnings("deprecation") From 7ccea997d5a09d4f503b219e37128abf6a609a0d Mon Sep 17 00:00:00 2001 From: Ran Date: Tue, 29 Oct 2019 15:17:10 -0700 Subject: [PATCH 123/131] Revert "stub: ignore unary response msg if status is not OK (#6288)" (#6342) (#6351) This reverts commit fe46edac (cherry picked from commit 258a95d0c4451a2ca1055358cb41d09c034ee6b4) --- .../main/java/io/grpc/stub/ClientCalls.java | 29 +---- .../java/io/grpc/stub/ClientCallsTest.java | 117 ------------------ 2 files changed, 2 insertions(+), 144 deletions(-) diff --git a/stub/src/main/java/io/grpc/stub/ClientCalls.java b/stub/src/main/java/io/grpc/stub/ClientCalls.java index 7240e122d2a..cf770a991e1 100644 --- a/stub/src/main/java/io/grpc/stub/ClientCalls.java +++ b/stub/src/main/java/io/grpc/stub/ClientCalls.java @@ -401,7 +401,6 @@ private static final class StreamObserverToCallListenerAdapter private final CallToStreamObserverAdapter adapter; private final boolean streamingResponse; private boolean firstResponseReceived; - private RespT unaryMessage; // Non private to avoid synthetic class StreamObserverToCallListenerAdapter( @@ -432,13 +431,7 @@ public void onMessage(RespT message) { .asRuntimeException(); } firstResponseReceived = true; - - if (streamingResponse) { - observer.onNext(message); - } else { - // will send message in onClose() for unary calls. - unaryMessage = message; - } + observer.onNext(message); if (streamingResponse && adapter.autoFlowControlEnabled) { // Request delivery of the next inbound message. @@ -448,28 +441,10 @@ public void onMessage(RespT message) { @Override public void onClose(Status status, Metadata trailers) { - Throwable error = null; if (status.isOk()) { - if (!streamingResponse) { - if (unaryMessage != null) { - try { - observer.onNext(unaryMessage); - } catch (Throwable t) { - error = t; - } - } else { - error = Status.INTERNAL.withDescription("Response message is null for unary call") - .asRuntimeException(); - } - } - } else { - error = status.asRuntimeException(trailers); - } - - if (error == null) { observer.onCompleted(); } else { - observer.onError(error); + observer.onError(status.asRuntimeException(trailers)); } } diff --git a/stub/src/test/java/io/grpc/stub/ClientCallsTest.java b/stub/src/test/java/io/grpc/stub/ClientCallsTest.java index bcae5340a2c..a6364877063 100644 --- a/stub/src/test/java/io/grpc/stub/ClientCallsTest.java +++ b/stub/src/test/java/io/grpc/stub/ClientCallsTest.java @@ -99,123 +99,6 @@ public void tearDown() { } } - @Test - public void unaryAsyncCallStatusIsOkWithMessageSuccess() throws Exception { - Integer req = 2; - final String resp = "bar"; - final Status status = Status.OK; - final Metadata trailers = new Metadata(); - final List actualResponse = new ArrayList<>(); - final List completed = new ArrayList<>(); - - NoopClientCall call = new NoopClientCall() { - @Override - public void start(ClientCall.Listener listener, Metadata headers) { - listener.onMessage(resp); - listener.onClose(status, trailers); - } - }; - - StreamObserver responseObserver = new StreamObserver() { - @Override - public void onNext(String value) { - actualResponse.add(value); - } - - @Override - public void onError(Throwable t) { - fail("Should not reach here"); - } - - @Override - public void onCompleted() { - completed.add(true); - } - }; - - ClientCalls.asyncUnaryCall(call, req, responseObserver); - assertThat(actualResponse).hasSize(1); - assertEquals(resp, actualResponse.get(0)); - assertThat(completed).hasSize(1); - assertThat(completed.get(0)).isTrue(); - } - - @Test - public void unaryAsyncCallStatusIsOkWithNullMessageGetError() throws Exception { - Integer req = 2; - final Status status = Status.OK; - final Metadata trailers = new Metadata(); - final List expected = new ArrayList<>(); - - NoopClientCall call = new NoopClientCall() { - @Override - public void start(ClientCall.Listener listener, Metadata headers) { - listener.onMessage(null); - listener.onClose(status, trailers); - } - }; - - StreamObserver responseObserver = new StreamObserver() { - @Override - public void onNext(String value) { - fail("Should not reach here"); - } - - @Override - public void onError(Throwable t) { - expected.add(t); - } - - @Override - public void onCompleted() { - fail("Should not reach here"); - } - }; - - ClientCalls.asyncUnaryCall(call, req, responseObserver); - assertThat(expected).hasSize(1); - assertThat(expected.get(0)).hasMessageThat() - .isEqualTo("INTERNAL: Response message is null for unary call"); - } - - @Test - public void unaryAsyncCallStatusIsNotOkWithMessageDoNotSendMessage() throws Exception { - Integer req = 2; - final Status status = Status.INTERNAL.withDescription("Unique status"); - final String resp = "bar"; - final Metadata trailers = new Metadata(); - final List expected = new ArrayList<>(); - - NoopClientCall call = new NoopClientCall() { - @Override - public void start(io.grpc.ClientCall.Listener listener, Metadata headers) { - listener.onMessage(resp); - listener.onClose(status, trailers); - } - }; - - StreamObserver responseObserver = new StreamObserver() { - @Override - public void onNext(String value) { - fail("Should not reach here"); - } - - @Override - public void onError(Throwable t) { - expected.add(t); - } - - @Override - public void onCompleted() { - fail("Should not reach here"); - } - }; - - ClientCalls.asyncUnaryCall(call, req, responseObserver); - assertThat(expected).hasSize(1); - assertThat(expected.get(0)).hasMessageThat().isEqualTo("INTERNAL: Unique status"); - } - @Test public void unaryBlockingCallSuccess() throws Exception { Integer req = 2; From ca620e5016473e0b590b63e6dba758cd2da251b9 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 31 Oct 2019 16:18:30 -0700 Subject: [PATCH 124/131] interop-testing,benchmarks: publish tar, zip --- benchmarks/build.gradle | 9 +++++++++ interop-testing/build.gradle | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/benchmarks/build.gradle b/benchmarks/build.gradle index 7aef7870e3f..444f36477f6 100644 --- a/benchmarks/build.gradle +++ b/benchmarks/build.gradle @@ -100,3 +100,12 @@ applicationDistribution.into("bin") { from(benchmark_worker) fileMode = 0755 } + +publishing { + publications { + maven(MavenPublication) { + artifact distZip + artifact distTar + } + } +} diff --git a/interop-testing/build.gradle b/interop-testing/build.gradle index 12c571e31cc..b11ed26ebc8 100644 --- a/interop-testing/build.gradle +++ b/interop-testing/build.gradle @@ -120,3 +120,12 @@ applicationDistribution.into("bin") { from(grpclb_long_lived_affinity_test_client) fileMode = 0755 } + +publishing { + publications { + maven(MavenPublication) { + artifact distZip + artifact distTar + } + } +} From bad61239527c4f35722228a25636db5ba52cf38d Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Fri, 1 Nov 2019 12:30:37 -0700 Subject: [PATCH 125/131] alts: Check Cipher before declaring Conscrypt working --- .../grpc/alts/internal/AesGcmAeadCrypter.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java b/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java index bd072eab42c..fa9cc91e1ee 100644 --- a/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java +++ b/alts/src/main/java/io/grpc/alts/internal/AesGcmAeadCrypter.java @@ -121,11 +121,36 @@ private static Provider getConscrypt() { // // While we could use Conscrypt.version() to check compatibility, that is _very_ verbose via // reflection. In practice, old conscrypts are probably not much of a problem. + Provider provider; try { - return ConscryptLoader.newProvider(); + provider = ConscryptLoader.newProvider(); } catch (Throwable t) { logger.log(Level.INFO, "Could not load Conscrypt. Will use slower JDK implementation", t); return null; } + try { + Cipher.getInstance(AES_GCM, CONSCRYPT); + } catch (SecurityException t) { + // Pre-Java 7u121/Java 8u111 fails with SecurityException: + // JCE cannot authenticate the provider Conscrypt + // + // This is because Conscrypt uses a newer (more secure) signing CA than the earlier Java + // supported. https://www.oracle.com/technetwork/java/javase/8u111-relnotes-3124969.html + // https://www.oracle.com/technetwork/java/javase/documentation/javase7supportreleasenotes-1601161.html#R170_121 + // + // Use WARNING instead of INFO in this case because it is unlikely to be a supported + // environment. In the other cases we might be on Java 9+; it seems unlikely in this case. + // Note that on Java 7, we're likely to crash later because GCM is unsupported. + logger.log( + Level.WARNING, + "Could not load Conscrypt. Will try slower JDK implementation. This may be because the " + + "JDK is older than Java 7 update 121 or Java 8 update 111. If so, please update", + t); + return null; + } catch (Throwable t) { + logger.log(Level.INFO, "Could not load Conscrypt. Will use slower JDK implementation", t); + return null; + } + return provider; } } From f737840985571436698cab83f83e24a6daba5899 Mon Sep 17 00:00:00 2001 From: ZHANG Dapeng Date: Fri, 1 Nov 2019 12:04:52 -0700 Subject: [PATCH 126/131] alts: fix ComputeEngineChannelBuilder class signature --- .../src/main/java/io/grpc/alts/ComputeEngineChannelBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alts/src/main/java/io/grpc/alts/ComputeEngineChannelBuilder.java b/alts/src/main/java/io/grpc/alts/ComputeEngineChannelBuilder.java index f12de57a8a2..d9eaba8cc7c 100644 --- a/alts/src/main/java/io/grpc/alts/ComputeEngineChannelBuilder.java +++ b/alts/src/main/java/io/grpc/alts/ComputeEngineChannelBuilder.java @@ -39,7 +39,7 @@ * using ALTS if applicable and using TLS as fallback. */ public final class ComputeEngineChannelBuilder - extends ForwardingChannelBuilder { + extends ForwardingChannelBuilder { private final NettyChannelBuilder delegate; From 78efc8b4331bd32a5f580a29b5b72eae80f7b17a Mon Sep 17 00:00:00 2001 From: Eric Anderson Date: Mon, 4 Nov 2019 11:33:02 -0800 Subject: [PATCH 127/131] api: Rename blockingExecutor to offloadExecutor The API review for #6279 came up with a more meaningful name that better explains the intent. A setter for the old name was left in ManagedChannelBuilder to ease migration to the new name by current users. --- .../java/io/grpc/ForwardingChannelBuilder.java | 7 +++++++ .../main/java/io/grpc/ManagedChannelBuilder.java | 10 ++++++++-- api/src/main/java/io/grpc/NameResolver.java | 8 ++++---- api/src/test/java/io/grpc/NameResolverTest.java | 6 +++--- .../AbstractManagedChannelImplBuilder.java | 8 ++++---- .../java/io/grpc/internal/DnsNameResolver.java | 2 +- .../io/grpc/internal/ManagedChannelImpl.java | 14 +++++++------- .../AbstractManagedChannelImplBuilderTest.java | 16 ++++++++-------- .../io/grpc/internal/DnsNameResolverTest.java | 2 +- .../io/grpc/internal/ManagedChannelImplTest.java | 10 +++++----- 10 files changed, 48 insertions(+), 35 deletions(-) diff --git a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java index 4ef944c7ab9..cbbe50d1b3b 100644 --- a/api/src/main/java/io/grpc/ForwardingChannelBuilder.java +++ b/api/src/main/java/io/grpc/ForwardingChannelBuilder.java @@ -71,6 +71,13 @@ public T executor(Executor executor) { return thisT(); } + @Override + public T offloadExecutor(Executor executor) { + delegate().offloadExecutor(executor); + return thisT(); + } + + @Deprecated @Override public T blockingExecutor(Executor executor) { delegate().blockingExecutor(executor); diff --git a/api/src/main/java/io/grpc/ManagedChannelBuilder.java b/api/src/main/java/io/grpc/ManagedChannelBuilder.java index cfb626b6648..72cf0c909cb 100644 --- a/api/src/main/java/io/grpc/ManagedChannelBuilder.java +++ b/api/src/main/java/io/grpc/ManagedChannelBuilder.java @@ -104,7 +104,7 @@ public static ManagedChannelBuilder forTarget(String target) { public abstract T executor(Executor executor); /** - * Provides a custom executor that will be used for operations that block. + * Provides a custom executor that will be used for operations that block or are expensive. * *

    It's an optional parameter. If the user has not provided an executor when the channel is * built, the builder will use a static cached thread pool. @@ -117,10 +117,16 @@ public static ManagedChannelBuilder forTarget(String target) { * @since 1.25.0 */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") - public T blockingExecutor(Executor executor) { + public T offloadExecutor(Executor executor) { throw new UnsupportedOperationException(); } + @Deprecated + @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") + public T blockingExecutor(Executor executor) { + return offloadExecutor(executor); + } + /** * Adds interceptors that will be called before the channel performs its real work. This is * functionally equivalent to using {@link ClientInterceptors#intercept(Channel, List)}, but while diff --git a/api/src/main/java/io/grpc/NameResolver.java b/api/src/main/java/io/grpc/NameResolver.java index 459f74fe50c..463c44eea9d 100644 --- a/api/src/main/java/io/grpc/NameResolver.java +++ b/api/src/main/java/io/grpc/NameResolver.java @@ -474,7 +474,7 @@ public ServiceConfigParser getServiceConfigParser() { */ @Nullable @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") - public Executor getBlockingExecutor() { + public Executor getOffloadExecutor() { return executor; } @@ -500,7 +500,7 @@ public Builder toBuilder() { builder.setProxyDetector(proxyDetector); builder.setSynchronizationContext(syncContext); builder.setServiceConfigParser(serviceConfigParser); - builder.setBlockingExecutor(executor); + builder.setOffloadExecutor(executor); return builder; } @@ -569,12 +569,12 @@ public Builder setServiceConfigParser(ServiceConfigParser parser) { } /** - * See {@link Args#getBlockingExecutor}. This is an optional field. + * See {@link Args#getOffloadExecutor}. This is an optional field. * * @since 1.25.0 */ @ExperimentalApi("https://github.com/grpc/grpc-java/issues/6279") - public Builder setBlockingExecutor(Executor executor) { + public Builder setOffloadExecutor(Executor executor) { this.executor = executor; return this; } diff --git a/api/src/test/java/io/grpc/NameResolverTest.java b/api/src/test/java/io/grpc/NameResolverTest.java index 09e1e1c20f6..3206f4be4ae 100644 --- a/api/src/test/java/io/grpc/NameResolverTest.java +++ b/api/src/test/java/io/grpc/NameResolverTest.java @@ -61,14 +61,14 @@ public void args() { assertThat(args.getProxyDetector()).isSameInstanceAs(proxyDetector); assertThat(args.getSynchronizationContext()).isSameInstanceAs(syncContext); assertThat(args.getServiceConfigParser()).isSameInstanceAs(parser); - assertThat(args.getBlockingExecutor()).isSameInstanceAs(executor); + assertThat(args.getOffloadExecutor()).isSameInstanceAs(executor); NameResolver.Args args2 = args.toBuilder().build(); assertThat(args2.getDefaultPort()).isEqualTo(defaultPort); assertThat(args2.getProxyDetector()).isSameInstanceAs(proxyDetector); assertThat(args2.getSynchronizationContext()).isSameInstanceAs(syncContext); assertThat(args2.getServiceConfigParser()).isSameInstanceAs(parser); - assertThat(args2.getBlockingExecutor()).isSameInstanceAs(executor); + assertThat(args2.getOffloadExecutor()).isSameInstanceAs(executor); assertThat(args2).isNotSameInstanceAs(args); assertThat(args2).isNotEqualTo(args); @@ -251,7 +251,7 @@ private NameResolver.Args createArgs() { .setProxyDetector(proxyDetector) .setSynchronizationContext(syncContext) .setServiceConfigParser(parser) - .setBlockingExecutor(executor) + .setOffloadExecutor(executor) .build(); } } diff --git a/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java b/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java index 3698eda6fd1..cfdabdf2d89 100644 --- a/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java +++ b/core/src/main/java/io/grpc/internal/AbstractManagedChannelImplBuilder.java @@ -95,7 +95,7 @@ public static ManagedChannelBuilder forTarget(String target) { ObjectPool executorPool = DEFAULT_EXECUTOR_POOL; - ObjectPool blockingExecutorPool = DEFAULT_EXECUTOR_POOL; + ObjectPool offloadExecutorPool = DEFAULT_EXECUTOR_POOL; private final List interceptors = new ArrayList<>(); final NameResolverRegistry nameResolverRegistry = NameResolverRegistry.getDefaultRegistry(); @@ -220,11 +220,11 @@ public final T executor(Executor executor) { } @Override - public final T blockingExecutor(Executor executor) { + public final T offloadExecutor(Executor executor) { if (executor != null) { - this.blockingExecutorPool = new FixedObjectPool<>(executor); + this.offloadExecutorPool = new FixedObjectPool<>(executor); } else { - this.blockingExecutorPool = DEFAULT_EXECUTOR_POOL; + this.offloadExecutorPool = DEFAULT_EXECUTOR_POOL; } return thisT(); } diff --git a/core/src/main/java/io/grpc/internal/DnsNameResolver.java b/core/src/main/java/io/grpc/internal/DnsNameResolver.java index feb6d7d7767..2b638327cc9 100644 --- a/core/src/main/java/io/grpc/internal/DnsNameResolver.java +++ b/core/src/main/java/io/grpc/internal/DnsNameResolver.java @@ -185,7 +185,7 @@ final class DnsNameResolver extends NameResolver { this.stopwatch = Preconditions.checkNotNull(stopwatch, "stopwatch"); this.syncContext = Preconditions.checkNotNull(args.getSynchronizationContext(), "syncContext"); - this.executor = args.getBlockingExecutor(); + this.executor = args.getOffloadExecutor(); this.usingExecutorResource = executor == null; this.enableSrv = enableSrv; } diff --git a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java index fed1d660bc9..7114c774a96 100644 --- a/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java +++ b/core/src/main/java/io/grpc/internal/ManagedChannelImpl.java @@ -142,7 +142,7 @@ final class ManagedChannelImpl extends ManagedChannel implements private final ObjectPool executorPool; private final ObjectPool balancerRpcExecutorPool; private final ExecutorHolder balancerRpcExecutorHolder; - private final ExecutorHolder blockingExecutorHolder; + private final ExecutorHolder offloadExecutorHolder; private final TimeProvider timeProvider; private final int maxTraceEvents; @@ -566,9 +566,9 @@ ClientStream newSubstream(ClientStreamTracer.Factory tracerFactory, Metadata new builder.proxyDetector != null ? builder.proxyDetector : GrpcUtil.DEFAULT_PROXY_DETECTOR; this.retryEnabled = builder.retryEnabled && !builder.temporarilyDisableRetry; this.loadBalancerFactory = new AutoConfiguredLoadBalancerFactory(builder.defaultLbPolicy); - this.blockingExecutorHolder = + this.offloadExecutorHolder = new ExecutorHolder( - checkNotNull(builder.blockingExecutorPool, "blockingExecutorPool")); + checkNotNull(builder.offloadExecutorPool, "offloadExecutorPool")); this.nameResolverRegistry = builder.nameResolverRegistry; this.nameResolverArgs = NameResolver.Args.newBuilder() @@ -581,12 +581,12 @@ ClientStream newSubstream(ClientStreamTracer.Factory tracerFactory, Metadata new builder.maxRetryAttempts, builder.maxHedgedAttempts, loadBalancerFactory)) - .setBlockingExecutor( - // Avoid creating the blockingExecutor until it is first used + .setOffloadExecutor( + // Avoid creating the offloadExecutor until it is first used new Executor() { @Override public void execute(Runnable command) { - blockingExecutorHolder.getExecutor().execute(command); + offloadExecutorHolder.getExecutor().execute(command); } }) .build(); @@ -900,7 +900,7 @@ private void maybeTerminateChannel() { terminatedLatch.countDown(); executorPool.returnObject(executor); balancerRpcExecutorHolder.release(); - blockingExecutorHolder.release(); + offloadExecutorHolder.release(); // Release the transport factory so that it can deallocate any resources. transportFactory.close(); } diff --git a/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java b/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java index fee1685f8a2..8b454f974b0 100644 --- a/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java +++ b/core/src/test/java/io/grpc/internal/AbstractManagedChannelImplBuilderTest.java @@ -100,18 +100,18 @@ public void directExecutor() { } @Test - public void blockingExecutor_normal() { + public void offloadExecutor_normal() { Executor executor = mock(Executor.class); - assertEquals(builder, builder.blockingExecutor(executor)); - assertEquals(executor, builder.blockingExecutorPool.getObject()); + assertEquals(builder, builder.offloadExecutor(executor)); + assertEquals(executor, builder.offloadExecutorPool.getObject()); } @Test - public void blockingExecutor_null() { - ObjectPool defaultValue = builder.blockingExecutorPool; - builder.blockingExecutor(mock(Executor.class)); - assertEquals(builder, builder.blockingExecutor(null)); - assertEquals(defaultValue, builder.blockingExecutorPool); + public void offloadExecutor_null() { + ObjectPool defaultValue = builder.offloadExecutorPool; + builder.offloadExecutor(mock(Executor.class)); + assertEquals(builder, builder.offloadExecutor(null)); + assertEquals(defaultValue, builder.offloadExecutorPool); } @Test diff --git a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java index 6baa87ad0ad..4edc2473dac 100644 --- a/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java +++ b/core/src/test/java/io/grpc/internal/DnsNameResolverTest.java @@ -331,7 +331,7 @@ public void testExecutor_custom() throws Exception { .setProxyDetector(GrpcUtil.NOOP_PROXY_DETECTOR) .setSynchronizationContext(syncContext) .setServiceConfigParser(mock(ServiceConfigParser.class)) - .setBlockingExecutor( + .setOffloadExecutor( new Executor() { @Override public void execute(Runnable command) { diff --git a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java index b2eb58dc108..e2d7ba70f78 100644 --- a/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java +++ b/core/src/test/java/io/grpc/internal/ManagedChannelImplTest.java @@ -266,7 +266,7 @@ public String getPolicyName() { @Mock private CallCredentials creds; @Mock - private Executor blockingExecutor; + private Executor offloadExecutor; private ChannelBuilder channelBuilder; private boolean requestConnection = true; private BlockingQueue transports; @@ -328,7 +328,7 @@ public void setUp() throws Exception { .userAgent(USER_AGENT) .idleTimeout( AbstractManagedChannelImplBuilder.IDLE_MODE_MAX_TIMEOUT_DAYS, TimeUnit.DAYS) - .blockingExecutor(blockingExecutor); + .offloadExecutor(offloadExecutor); channelBuilder.executorPool = executorPool; channelBuilder.binlog = null; channelBuilder.channelz = channelz; @@ -3588,14 +3588,14 @@ public String getDefaultScheme() { assertThat(args.getDefaultPort()).isEqualTo(DEFAULT_PORT); assertThat(args.getProxyDetector()).isSameInstanceAs(neverProxy); - verify(blockingExecutor, never()).execute(any(Runnable.class)); - args.getBlockingExecutor() + verify(offloadExecutor, never()).execute(any(Runnable.class)); + args.getOffloadExecutor() .execute( new Runnable() { @Override public void run() {} }); - verify(blockingExecutor, times(1)).execute(any(Runnable.class)); + verify(offloadExecutor, times(1)).execute(any(Runnable.class)); } @Test From 4dde588c081154f65bfb13c442bcc47c6c3eaf27 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 24 Oct 2019 14:06:25 -0700 Subject: [PATCH 128/131] okhttp: use FINE log for pure IOExceptions --- .../grpc/okhttp/ExceptionHandlingFrameWriter.java | 12 +----------- .../okhttp/ExceptionHandlingFrameWriterTest.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/okhttp/src/main/java/io/grpc/okhttp/ExceptionHandlingFrameWriter.java b/okhttp/src/main/java/io/grpc/okhttp/ExceptionHandlingFrameWriter.java index 93a4c740e84..9f7074121fc 100644 --- a/okhttp/src/main/java/io/grpc/okhttp/ExceptionHandlingFrameWriter.java +++ b/okhttp/src/main/java/io/grpc/okhttp/ExceptionHandlingFrameWriter.java @@ -25,11 +25,7 @@ import io.grpc.okhttp.internal.framed.Header; import io.grpc.okhttp.internal.framed.Settings; import java.io.IOException; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import okio.Buffer; @@ -39,10 +35,6 @@ final class ExceptionHandlingFrameWriter implements FrameWriter { private static final Logger log = Logger.getLogger(OkHttpClientTransport.class.getName()); - // Some exceptions are not very useful and add too much noise to the log - private static final Set QUIET_ERRORS = - Collections.unmodifiableSet(new HashSet<>(Arrays.asList("Socket closed"))); - private final TransportExceptionHandler transportExceptionHandler; private final FrameWriter frameWriter; @@ -231,9 +223,7 @@ public void close() { */ @VisibleForTesting static Level getLogLevel(Throwable t) { - if (t instanceof IOException - && t.getMessage() != null - && QUIET_ERRORS.contains(t.getMessage())) { + if (t.getClass().equals(IOException.class)) { return Level.FINE; } return Level.INFO; diff --git a/okhttp/src/test/java/io/grpc/okhttp/ExceptionHandlingFrameWriterTest.java b/okhttp/src/test/java/io/grpc/okhttp/ExceptionHandlingFrameWriterTest.java index 27e3c0fc3fb..c26edcd0df8 100644 --- a/okhttp/src/test/java/io/grpc/okhttp/ExceptionHandlingFrameWriterTest.java +++ b/okhttp/src/test/java/io/grpc/okhttp/ExceptionHandlingFrameWriterTest.java @@ -71,18 +71,22 @@ public void unknownException() { } @Test - public void quiet() { + public void ioException() { assertThat(getLogLevel(new IOException("Socket closed"))).isEqualTo(Level.FINE); } @Test - public void nonquiet() { - assertThat(getLogLevel(new IOException("foo"))).isEqualTo(Level.INFO); + public void ioException_nullMessage() { + IOException e = new IOException(); + assertThat(e.getMessage()).isNull(); + assertThat(getLogLevel(e)).isEqualTo(Level.FINE); } @Test - public void nullMessage() { - IOException e = new IOException(); + public void extendedIoException() { + class ExtendedIoException extends IOException {} + + ExtendedIoException e = new ExtendedIoException(); assertThat(e.getMessage()).isNull(); assertThat(getLogLevel(e)).isEqualTo(Level.INFO); } From 89eef59df657ee478ce2107ee1cdf3d39adc45b8 Mon Sep 17 00:00:00 2001 From: Jihun Cho Date: Thu, 24 Oct 2019 14:06:16 -0700 Subject: [PATCH 129/131] netty: use FINE log for pure IOExceptions --- .../io/grpc/netty/NettyServerTransport.java | 14 ++--------- .../grpc/netty/NettyServerTransportTest.java | 23 +++++++++---------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java index 7030aa3ef1d..f22ff97a32c 100644 --- a/netty/src/main/java/io/grpc/netty/NettyServerTransport.java +++ b/netty/src/main/java/io/grpc/netty/NettyServerTransport.java @@ -19,7 +19,6 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.SettableFuture; import io.grpc.InternalChannelz.SocketStats; @@ -50,11 +49,6 @@ class NettyServerTransport implements ServerTransport { // connectionLog is for connection related messages only private static final Logger connectionLog = Logger.getLogger( String.format("%s.connections", NettyServerTransport.class.getName())); - // Some exceptions are not very useful and add too much noise to the log - private static final ImmutableList QUIET_ERRORS = ImmutableList.of( - "Connection reset by peer", - "An existing connection was forcibly closed by the remote host", - "An established connection was aborted by the software in your host machine"); private final InternalLogId logId; private final Channel channel; @@ -184,12 +178,8 @@ Channel channel() { */ @VisibleForTesting static Level getLogLevel(Throwable t) { - if (t instanceof IOException && t.getMessage() != null) { - for (String msg : QUIET_ERRORS) { - if (t.getMessage().contains(msg)) { - return Level.FINE; - } - } + if (t.getClass().equals(IOException.class)) { + return Level.FINE; } return Level.INFO; } diff --git a/netty/src/test/java/io/grpc/netty/NettyServerTransportTest.java b/netty/src/test/java/io/grpc/netty/NettyServerTransportTest.java index d4ccbb089e2..71b0723157f 100644 --- a/netty/src/test/java/io/grpc/netty/NettyServerTransportTest.java +++ b/netty/src/test/java/io/grpc/netty/NettyServerTransportTest.java @@ -16,6 +16,7 @@ package io.grpc.netty; +import static com.google.common.truth.Truth.assertThat; import static io.grpc.netty.NettyServerTransport.getLogLevel; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; @@ -34,27 +35,25 @@ public void unknownException() { } @Test - public void quiet() { + public void ioException() { assertEquals(Level.FINE, getLogLevel(new IOException("Connection reset by peer"))); assertEquals(Level.FINE, getLogLevel(new IOException( "An existing connection was forcibly closed by the remote host"))); } @Test - public void quiet_prefixed() { - assertEquals(Level.FINE, getLogLevel(new IOException( - "syscall:read(..) failed: Connection reset by peer"))); + public void ioException_nullMessage() { + IOException e = new IOException(); + assertNull(e.getMessage()); + assertEquals(Level.FINE, getLogLevel(e)); } @Test - public void nonquiet() { - assertEquals(Level.INFO, getLogLevel(new IOException("foo"))); - } + public void extendedIoException() { + class ExtendedIoException extends IOException {} - @Test - public void nullMessage() { - IOException e = new IOException(); - assertNull(e.getMessage()); - assertEquals(Level.INFO, getLogLevel(e)); + ExtendedIoException e = new ExtendedIoException(); + assertThat(e.getMessage()).isNull(); + assertThat(getLogLevel(e)).isEqualTo(Level.INFO); } } From 82d56f1fbb22a2ce4add177d40aa022fcddbedda Mon Sep 17 00:00:00 2001 From: Kun Zhang Date: Tue, 5 Nov 2019 12:12:46 -0800 Subject: [PATCH 130/131] Update README etc to reference 1.25.0 --- README.md | 28 ++++++++++++------------ cronet/README.md | 2 +- documentation/android-channel-builder.md | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b2a7fc5c8bb..5d503256eb9 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ For a guided tour, take a look at the [quick start guide](https://grpc.io/docs/quickstart/java.html) or the more explanatory [gRPC basics](https://grpc.io/docs/tutorials/basic/java.html). -The [examples](https://github.com/grpc/grpc-java/tree/v1.24.0/examples) and the -[Android example](https://github.com/grpc/grpc-java/tree/v1.24.0/examples/android) +The [examples](https://github.com/grpc/grpc-java/tree/v1.25.0/examples) and the +[Android example](https://github.com/grpc/grpc-java/tree/v1.25.0/examples/android) are standalone projects that showcase the usage of gRPC. Download @@ -42,37 +42,37 @@ Download [the JARs][]. Or for Maven with non-Android, add to your `pom.xml`: io.grpc grpc-netty-shaded - 1.24.0 + 1.25.0 io.grpc grpc-protobuf - 1.24.0 + 1.25.0 io.grpc grpc-stub - 1.24.0 + 1.25.0 ``` Or for Gradle with non-Android, add to your dependencies: ```gradle -implementation 'io.grpc:grpc-netty-shaded:1.24.0' -implementation 'io.grpc:grpc-protobuf:1.24.0' -implementation 'io.grpc:grpc-stub:1.24.0' +implementation 'io.grpc:grpc-netty-shaded:1.25.0' +implementation 'io.grpc:grpc-protobuf:1.25.0' +implementation 'io.grpc:grpc-stub:1.25.0' ``` For Android client, use `grpc-okhttp` instead of `grpc-netty-shaded` and `grpc-protobuf-lite` instead of `grpc-protobuf`: ```gradle -implementation 'io.grpc:grpc-okhttp:1.24.0' -implementation 'io.grpc:grpc-protobuf-lite:1.24.0' -implementation 'io.grpc:grpc-stub:1.24.0' +implementation 'io.grpc:grpc-okhttp:1.25.0' +implementation 'io.grpc:grpc-protobuf-lite:1.25.0' +implementation 'io.grpc:grpc-stub:1.25.0' ``` [the JARs]: -https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.24.0 +https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.25.0 Development snapshots are available in [Sonatypes's snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/). @@ -104,7 +104,7 @@ For protobuf-based codegen integrated with the Maven build system, you can use com.google.protobuf:protoc:3.10.0:exe:${os.detected.classifier} grpc-java - io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier} + io.grpc:protoc-gen-grpc-java:1.25.0:exe:${os.detected.classifier} @@ -134,7 +134,7 @@ protobuf { } plugins { grpc { - artifact = 'io.grpc:protoc-gen-grpc-java:1.24.0' + artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' } } generateProtoTasks { diff --git a/cronet/README.md b/cronet/README.md index 613f3fb265c..994c24b218f 100644 --- a/cronet/README.md +++ b/cronet/README.md @@ -26,7 +26,7 @@ In your app module's `build.gradle` file, include a dependency on both `grpc-cro Google Play Services Client Library for Cronet ``` -implementation 'io.grpc:grpc-cronet:1.24.0' +implementation 'io.grpc:grpc-cronet:1.25.0' implementation 'com.google.android.gms:play-services-cronet:16.0.0' ``` diff --git a/documentation/android-channel-builder.md b/documentation/android-channel-builder.md index eb006c3c361..a57c4e75f75 100644 --- a/documentation/android-channel-builder.md +++ b/documentation/android-channel-builder.md @@ -36,8 +36,8 @@ In your `build.gradle` file, include a dependency on both `grpc-android` and `grpc-okhttp`: ``` -implementation 'io.grpc:grpc-android:1.24.0' -implementation 'io.grpc:grpc-okhttp:1.24.0' +implementation 'io.grpc:grpc-android:1.25.0' +implementation 'io.grpc:grpc-okhttp:1.25.0' ``` You will also need permission to access the device's network state in your From e086c0f0abfaa1897cac7b2ca30c52b52c3fdc7a Mon Sep 17 00:00:00 2001 From: Kun Zhang Date: Tue, 5 Nov 2019 12:18:36 -0800 Subject: [PATCH 131/131] Bump version to 1.25.0 --- android-interop-testing/app/build.gradle | 12 ++++++------ android/build.gradle | 6 +++--- build.gradle | 2 +- .../src/test/golden/TestDeprecatedService.java.txt | 2 +- compiler/src/test/golden/TestService.java.txt | 2 +- .../testLite/golden/TestDeprecatedService.java.txt | 2 +- compiler/src/testLite/golden/TestService.java.txt | 2 +- core/src/main/java/io/grpc/internal/GrpcUtil.java | 2 +- cronet/build.gradle | 6 +++--- examples/android/clientcache/app/build.gradle | 10 +++++----- examples/android/helloworld/app/build.gradle | 8 ++++---- examples/android/routeguide/app/build.gradle | 8 ++++---- examples/android/strictmode/app/build.gradle | 8 ++++---- examples/build.gradle | 2 +- examples/example-alts/build.gradle | 2 +- examples/example-gauth/build.gradle | 2 +- examples/example-gauth/pom.xml | 4 ++-- .../android/helloworld/app/build.gradle | 8 ++++---- examples/example-kotlin/build.gradle | 2 +- examples/example-tls/build.gradle | 2 +- examples/example-tls/pom.xml | 4 ++-- examples/pom.xml | 4 ++-- 22 files changed, 50 insertions(+), 50 deletions(-) diff --git a/android-interop-testing/app/build.gradle b/android-interop-testing/app/build.gradle index ea4e83ec760..fab12816ae4 100644 --- a/android-interop-testing/app/build.gradle +++ b/android-interop-testing/app/build.gradle @@ -42,7 +42,7 @@ protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -71,11 +71,11 @@ dependencies { implementation 'junit:junit:4.12' // You need to build grpc-java to obtain the grpc libraries below. - implementation 'io.grpc:grpc-auth:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-testing:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-auth:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-testing:1.25.0' // CURRENT_GRPC_VERSION // workaround for https://github.com/google/protobuf/issues/1889 protobuf 'com.google.protobuf:protobuf-java:3.0.2' diff --git a/android/build.gradle b/android/build.gradle index 4889c8c63b7..b4ecfbeabe8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' group = "io.grpc" -version = "1.25.0-SNAPSHOT" // CURRENT_GRPC_VERSION +version = "1.25.0" // CURRENT_GRPC_VERSION description = 'gRPC: Android' buildscript { @@ -47,9 +47,9 @@ dependencies { errorprone 'com.google.errorprone:error_prone_core:2.3.3' errorproneJavac 'com.google.errorprone:javac:9+181-r4173-1' - implementation 'io.grpc:grpc-core:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-core:1.25.0' // CURRENT_GRPC_VERSION - testImplementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + testImplementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:3.7.1' testImplementation 'com.google.truth:truth:1.0' diff --git a/build.gradle b/build.gradle index 2dc5a4a347c..d02d0a016b4 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,7 @@ subprojects { apply plugin: "net.ltgt.errorprone" group = "io.grpc" - version = "1.25.0-SNAPSHOT" // CURRENT_GRPC_VERSION + version = "1.25.0" // CURRENT_GRPC_VERSION repositories { maven { // The google mirror is less flaky than mavenCentral() diff --git a/compiler/src/test/golden/TestDeprecatedService.java.txt b/compiler/src/test/golden/TestDeprecatedService.java.txt index a57999ac0b8..aaeeb2d2415 100644 --- a/compiler/src/test/golden/TestDeprecatedService.java.txt +++ b/compiler/src/test/golden/TestDeprecatedService.java.txt @@ -21,7 +21,7 @@ import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.25.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.25.0)", comments = "Source: grpc/testing/compiler/test.proto") @java.lang.Deprecated public final class TestDeprecatedServiceGrpc { diff --git a/compiler/src/test/golden/TestService.java.txt b/compiler/src/test/golden/TestService.java.txt index b6324715568..d435c7669e4 100644 --- a/compiler/src/test/golden/TestService.java.txt +++ b/compiler/src/test/golden/TestService.java.txt @@ -21,7 +21,7 @@ import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.25.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.25.0)", comments = "Source: grpc/testing/compiler/test.proto") public final class TestServiceGrpc { diff --git a/compiler/src/testLite/golden/TestDeprecatedService.java.txt b/compiler/src/testLite/golden/TestDeprecatedService.java.txt index 6d59a415592..ad1fb348102 100644 --- a/compiler/src/testLite/golden/TestDeprecatedService.java.txt +++ b/compiler/src/testLite/golden/TestDeprecatedService.java.txt @@ -21,7 +21,7 @@ import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.25.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.25.0)", comments = "Source: grpc/testing/compiler/test.proto") @java.lang.Deprecated public final class TestDeprecatedServiceGrpc { diff --git a/compiler/src/testLite/golden/TestService.java.txt b/compiler/src/testLite/golden/TestService.java.txt index 2bd085fbc19..bbc23ca5f61 100644 --- a/compiler/src/testLite/golden/TestService.java.txt +++ b/compiler/src/testLite/golden/TestService.java.txt @@ -21,7 +21,7 @@ import static io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall; * */ @javax.annotation.Generated( - value = "by gRPC proto compiler (version 1.25.0-SNAPSHOT)", + value = "by gRPC proto compiler (version 1.25.0)", comments = "Source: grpc/testing/compiler/test.proto") public final class TestServiceGrpc { diff --git a/core/src/main/java/io/grpc/internal/GrpcUtil.java b/core/src/main/java/io/grpc/internal/GrpcUtil.java index 463db7b5a39..b00edea1053 100644 --- a/core/src/main/java/io/grpc/internal/GrpcUtil.java +++ b/core/src/main/java/io/grpc/internal/GrpcUtil.java @@ -195,7 +195,7 @@ public byte[] parseAsciiString(byte[] serialized) { public static final Splitter ACCEPT_ENCODING_SPLITTER = Splitter.on(',').trimResults(); - private static final String IMPLEMENTATION_VERSION = "1.25.0-SNAPSHOT"; // CURRENT_GRPC_VERSION + private static final String IMPLEMENTATION_VERSION = "1.25.0"; // CURRENT_GRPC_VERSION /** * The default timeout in nanos for a keepalive ping request. diff --git a/cronet/build.gradle b/cronet/build.gradle index a5505083f39..0c32ec541ce 100644 --- a/cronet/build.gradle +++ b/cronet/build.gradle @@ -1,7 +1,7 @@ apply plugin: 'com.android.library' group = "io.grpc" -version = "1.25.0-SNAPSHOT" // CURRENT_GRPC_VERSION +version = "1.25.0" // CURRENT_GRPC_VERSION description = "gRPC: Cronet Android" buildscript { @@ -54,8 +54,8 @@ dependencies { errorprone 'com.google.errorprone:error_prone_core:2.3.3' errorproneJavac 'com.google.errorprone:javac:9+181-r4173-1' - implementation 'io.grpc:grpc-core:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - testImplementation 'io.grpc:grpc-testing:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-core:1.25.0' // CURRENT_GRPC_VERSION + testImplementation 'io.grpc:grpc-testing:1.25.0' // CURRENT_GRPC_VERSION implementation 'org.chromium.net:cronet-api:76.3809.111' testImplementation 'org.chromium.net:cronet-embedded:66.3359.158' diff --git a/examples/android/clientcache/app/build.gradle b/examples/android/clientcache/app/build.gradle index b497ed64512..956235f6b31 100644 --- a/examples/android/clientcache/app/build.gradle +++ b/examples/android/clientcache/app/build.gradle @@ -31,7 +31,7 @@ protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.4.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -49,12 +49,12 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.25.0' // CURRENT_GRPC_VERSION implementation 'javax.annotation:javax.annotation-api:1.2' testImplementation 'junit:junit:4.12' testImplementation 'com.google.truth:truth:1.0' - testImplementation 'io.grpc:grpc-testing:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + testImplementation 'io.grpc:grpc-testing:1.25.0' // CURRENT_GRPC_VERSION } diff --git a/examples/android/helloworld/app/build.gradle b/examples/android/helloworld/app/build.gradle index 05380eaa3ac..32c4cca6403 100644 --- a/examples/android/helloworld/app/build.gradle +++ b/examples/android/helloworld/app/build.gradle @@ -30,7 +30,7 @@ protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -48,8 +48,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.25.0' // CURRENT_GRPC_VERSION implementation 'javax.annotation:javax.annotation-api:1.2' } diff --git a/examples/android/routeguide/app/build.gradle b/examples/android/routeguide/app/build.gradle index 26c44dcddd8..89960dfd813 100644 --- a/examples/android/routeguide/app/build.gradle +++ b/examples/android/routeguide/app/build.gradle @@ -29,7 +29,7 @@ protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -47,8 +47,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:27.0.2' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.25.0' // CURRENT_GRPC_VERSION implementation 'javax.annotation:javax.annotation-api:1.2' } diff --git a/examples/android/strictmode/app/build.gradle b/examples/android/strictmode/app/build.gradle index 06a3091c35b..c2ee3df3f72 100644 --- a/examples/android/strictmode/app/build.gradle +++ b/examples/android/strictmode/app/build.gradle @@ -30,7 +30,7 @@ protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -48,8 +48,8 @@ dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.25.0' // CURRENT_GRPC_VERSION implementation 'javax.annotation:javax.annotation-api:1.2' } diff --git a/examples/build.gradle b/examples/build.gradle index 553e4f680a7..fa46aa65dc5 100644 --- a/examples/build.gradle +++ b/examples/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.25.0' // CURRENT_GRPC_VERSION def protobufVersion = '3.10.0' def protocVersion = protobufVersion diff --git a/examples/example-alts/build.gradle b/examples/example-alts/build.gradle index fcc6a13bc75..f9f6443dc58 100644 --- a/examples/example-alts/build.gradle +++ b/examples/example-alts/build.gradle @@ -22,7 +22,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.25.0' // CURRENT_GRPC_VERSION def protocVersion = '3.10.0' dependencies { diff --git a/examples/example-gauth/build.gradle b/examples/example-gauth/build.gradle index 3cdc6c0a9ea..4c212f5fa04 100644 --- a/examples/example-gauth/build.gradle +++ b/examples/example-gauth/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.25.0' // CURRENT_GRPC_VERSION def protobufVersion = '3.10.0' def protocVersion = protobufVersion diff --git a/examples/example-gauth/pom.xml b/examples/example-gauth/pom.xml index 232822d0122..78614985786 100644 --- a/examples/example-gauth/pom.xml +++ b/examples/example-gauth/pom.xml @@ -6,13 +6,13 @@ jar - 1.25.0-SNAPSHOT + 1.25.0 example-gauth https://github.com/grpc/grpc-java UTF-8 - 1.25.0-SNAPSHOT + 1.25.0 3.10.0 1.7 diff --git a/examples/example-kotlin/android/helloworld/app/build.gradle b/examples/example-kotlin/android/helloworld/app/build.gradle index 94af988101e..ff5398e07d8 100644 --- a/examples/example-kotlin/android/helloworld/app/build.gradle +++ b/examples/example-kotlin/android/helloworld/app/build.gradle @@ -52,7 +52,7 @@ protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.10.0' } plugins { javalite { artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0" } - grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.25.0' // CURRENT_GRPC_VERSION } } generateProtoTasks { @@ -72,9 +72,9 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" // You need to build grpc-java to obtain these libraries below. - implementation 'io.grpc:grpc-okhttp:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-protobuf-lite:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION - implementation 'io.grpc:grpc-stub:1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-okhttp:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-protobuf-lite:1.25.0' // CURRENT_GRPC_VERSION + implementation 'io.grpc:grpc-stub:1.25.0' // CURRENT_GRPC_VERSION } repositories { mavenCentral() } diff --git a/examples/example-kotlin/build.gradle b/examples/example-kotlin/build.gradle index 7410037ab60..5bde7cd3a31 100644 --- a/examples/example-kotlin/build.gradle +++ b/examples/example-kotlin/build.gradle @@ -25,7 +25,7 @@ repositories { // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.25.0' // CURRENT_GRPC_VERSION dependencies { def kotlinVersion = plugins.findPlugin("org.jetbrains.kotlin.jvm").kotlinPluginVersion diff --git a/examples/example-tls/build.gradle b/examples/example-tls/build.gradle index 37479d41cf5..7951c7e63ba 100644 --- a/examples/example-tls/build.gradle +++ b/examples/example-tls/build.gradle @@ -23,7 +23,7 @@ targetCompatibility = 1.7 // Feel free to delete the comment at the next line. It is just for safely // updating the version in our release process. -def grpcVersion = '1.25.0-SNAPSHOT' // CURRENT_GRPC_VERSION +def grpcVersion = '1.25.0' // CURRENT_GRPC_VERSION def nettyTcNativeVersion = '2.0.26.Final' def protocVersion = '3.10.0' diff --git a/examples/example-tls/pom.xml b/examples/example-tls/pom.xml index 6391c8719c3..1698b66b9d4 100644 --- a/examples/example-tls/pom.xml +++ b/examples/example-tls/pom.xml @@ -6,13 +6,13 @@ jar - 1.25.0-SNAPSHOT + 1.25.0 example-tls https://github.com/grpc/grpc-java UTF-8 - 1.25.0-SNAPSHOT + 1.25.0 3.10.0 2.0.25.Final diff --git a/examples/pom.xml b/examples/pom.xml index ea29e0f38e7..71f010f58fe 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -6,13 +6,13 @@ jar - 1.25.0-SNAPSHOT + 1.25.0 examples https://github.com/grpc/grpc-java UTF-8 - 1.25.0-SNAPSHOT + 1.25.0 3.10.0 3.10.0