Skip to content

Commit d139388

Browse files
committed
Postponed resources allocation
1 parent 904bea2 commit d139388

File tree

6 files changed

+262
-76
lines changed

6 files changed

+262
-76
lines changed

util/src/main/java/io/grpc/util/AdvancedTlsX509TrustManager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ public Builder setSslSocketAndEnginePeerVerifier(SslSocketAndEnginePeerVerifier
460460
return this;
461461
}
462462

463-
public AdvancedTlsX509TrustManager build() throws CertificateException {
463+
public AdvancedTlsX509TrustManager build() {
464464
return new AdvancedTlsX509TrustManager(this.verification, this.socketAndEnginePeerVerifier);
465465
}
466466
}

xds/src/main/java/io/grpc/xds/GrpcXdsTransportFactory.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public XdsTransport createForTest(ManagedChannel channel) {
5555
static class GrpcXdsTransport implements XdsTransport {
5656

5757
private final ManagedChannel channel;
58+
private final ResourceAllocatingChannelCredentials resourceAllocatingChannelCredentials;
5859
private final CallCredentials callCredentials;
5960

6061
public GrpcXdsTransport(Bootstrapper.ServerInfo serverInfo) {
@@ -69,6 +70,13 @@ public GrpcXdsTransport(ManagedChannel channel) {
6970
public GrpcXdsTransport(Bootstrapper.ServerInfo serverInfo, CallCredentials callCredentials) {
7071
String target = serverInfo.target();
7172
ChannelCredentials channelCredentials = (ChannelCredentials) serverInfo.implSpecificConfig();
73+
if (channelCredentials instanceof ResourceAllocatingChannelCredentials) {
74+
this.resourceAllocatingChannelCredentials =
75+
(ResourceAllocatingChannelCredentials) channelCredentials;
76+
channelCredentials = resourceAllocatingChannelCredentials.acquireChannelCredentials();
77+
} else {
78+
this.resourceAllocatingChannelCredentials = null;
79+
}
7280
this.channel = Grpc.newChannelBuilder(target, channelCredentials)
7381
.keepAliveTime(5, TimeUnit.MINUTES)
7482
.build();
@@ -78,6 +86,7 @@ public GrpcXdsTransport(Bootstrapper.ServerInfo serverInfo, CallCredentials call
7886
@VisibleForTesting
7987
public GrpcXdsTransport(ManagedChannel channel, CallCredentials callCredentials) {
8088
this.channel = checkNotNull(channel, "channel");
89+
this.resourceAllocatingChannelCredentials = null;
8190
this.callCredentials = callCredentials;
8291
}
8392

@@ -99,6 +108,9 @@ public <ReqT, RespT> StreamingCall<ReqT, RespT> createStreamingCall(
99108
@Override
100109
public void shutdown() {
101110
channel.shutdown();
111+
if (resourceAllocatingChannelCredentials != null) {
112+
resourceAllocatingChannelCredentials.releaseChannelCredentials();
113+
}
102114
}
103115

104116
private class XdsStreamingCall<ReqT, RespT> implements

xds/src/main/java/io/grpc/xds/ResourceAllocatingChannelCredentials.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package io.grpc.xds;
1818

1919
import com.google.common.base.Preconditions;
20+
import com.google.common.base.Supplier;
2021
import com.google.common.collect.ImmutableList;
2122
import io.grpc.ChannelCredentials;
23+
import io.grpc.internal.GrpcUtil;
2224
import java.io.Closeable;
2325

2426
/**
@@ -28,29 +30,47 @@
2830
*/
2931
public final class ResourceAllocatingChannelCredentials extends ChannelCredentials {
3032
public static ChannelCredentials create(
31-
ChannelCredentials channelCreds, ImmutableList<Closeable> resources) {
32-
return new ResourceAllocatingChannelCredentials(channelCreds, resources);
33+
ChannelCredentials channelCreds, Supplier<ImmutableList<Closeable>> resourcesSupplier) {
34+
return new ResourceAllocatingChannelCredentials(channelCreds, resourcesSupplier);
3335
}
3436

3537
private final ChannelCredentials channelCreds;
36-
private final ImmutableList<Closeable> resources;
38+
private final Supplier<ImmutableList<Closeable>> resourcesSupplier;
39+
private int refCount;
40+
private ImmutableList<Closeable> resourcesReleaser;
3741

3842
private ResourceAllocatingChannelCredentials(
39-
ChannelCredentials channelCreds, ImmutableList<Closeable> resources) {
43+
ChannelCredentials channelCreds, Supplier<ImmutableList<Closeable>> resourcesSupplier) {
4044
this.channelCreds = Preconditions.checkNotNull(channelCreds, "channelCreds");
41-
this.resources = Preconditions.checkNotNull(resources, "resources");
45+
this.resourcesSupplier = Preconditions.checkNotNull(resourcesSupplier, "resourcesSupplier");
46+
this.refCount = 0;
47+
this.resourcesReleaser = null;
4248
}
4349

44-
public ChannelCredentials getChannelCredentials() {
50+
public synchronized ChannelCredentials acquireChannelCredentials() {
51+
if (refCount++ == 0) {
52+
resourcesReleaser = resourcesSupplier.get();
53+
}
4554
return channelCreds;
4655
}
4756

48-
public ImmutableList<Closeable> getAllocatedResources() {
49-
return resources;
57+
public synchronized void releaseChannelCredentials() {
58+
if (--refCount == 0) {
59+
for (Closeable resource : resourcesReleaser) {
60+
GrpcUtil.closeQuietly(resource);
61+
}
62+
resourcesReleaser = null;
63+
}
64+
Preconditions.checkState(
65+
refCount >= 0, "Channel credentials were released more times than they were acquired");
5066
}
5167

68+
/**
69+
* Please use {@link #acquireChannelCredentials()} to get a shared instance of
70+
* {@code ChannelCredentials} for which stripped tokens can be obtained.
71+
*/
5272
@Override
5373
public ChannelCredentials withoutBearerTokens() {
54-
return channelCreds.withoutBearerTokens();
74+
throw new UnsupportedOperationException("Cannot get stripped tokens");
5575
}
5676
}

xds/src/main/java/io/grpc/xds/internal/TlsXdsCredentialsProvider.java

Lines changed: 93 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package io.grpc.xds.internal;
1818

19+
import com.google.common.base.Supplier;
1920
import com.google.common.collect.ImmutableList;
2021
import com.google.protobuf.Duration;
2122
import com.google.protobuf.util.Durations;
@@ -73,66 +74,36 @@ protected ChannelCredentials newChannelCredentials(Map<String, ?> jsonConfig) {
7374
}
7475
}
7576

76-
ImmutableList.Builder<Closeable> resourcesBuilder = ImmutableList.builder();
77-
ScheduledExecutorService scheduledExecutorService = null;
78-
7977
// use trust certificate file path from bootstrap config if provided; else use system default
8078
String rootCertPath = JsonUtil.getString(jsonConfig, ROOT_FILE_KEY);
79+
AdvancedTlsX509TrustManager trustManager = null;
8180
if (rootCertPath != null) {
82-
try {
83-
scheduledExecutorService = scheduledExecutorServiceFactory.create();
84-
AdvancedTlsX509TrustManager trustManager = AdvancedTlsX509TrustManager.newBuilder().build();
85-
Closeable trustManagerFuture = trustManager.updateTrustCredentials(
86-
new File(rootCertPath),
87-
refreshIntervalSeconds,
88-
TimeUnit.SECONDS,
89-
scheduledExecutorService);
90-
resourcesBuilder.add(trustManagerFuture);
91-
tlsChannelCredsBuilder.trustManager(trustManager);
92-
} catch (Exception e) {
93-
logger.log(Level.WARNING, "Unable to read root certificates", e);
94-
return null;
95-
}
81+
trustManager = AdvancedTlsX509TrustManager.newBuilder().build();
82+
tlsChannelCredsBuilder.trustManager(trustManager);
9683
}
9784

9885
// use certificate chain and private key file paths from bootstrap config if provided. Mind that
9986
// both JSON values must be either set (mTLS case) or both unset (TLS case)
10087
String certChainPath = JsonUtil.getString(jsonConfig, CERT_FILE_KEY);
10188
String privateKeyPath = JsonUtil.getString(jsonConfig, KEY_FILE_KEY);
89+
AdvancedTlsX509KeyManager keyManager = null;
10290
if (certChainPath != null && privateKeyPath != null) {
103-
try {
104-
if (scheduledExecutorService == null) {
105-
scheduledExecutorService = scheduledExecutorServiceFactory.create();
106-
}
107-
AdvancedTlsX509KeyManager keyManager = new AdvancedTlsX509KeyManager();
108-
Closeable keyManagerFuture = keyManager.updateIdentityCredentials(
109-
new File(certChainPath),
110-
new File(privateKeyPath),
111-
refreshIntervalSeconds,
112-
TimeUnit.SECONDS,
113-
scheduledExecutorService);
114-
resourcesBuilder.add(keyManagerFuture);
115-
tlsChannelCredsBuilder.keyManager(keyManager);
116-
} catch (Exception e) {
117-
logger.log(Level.WARNING, "Unable to read certificate chain or private key", e);
118-
return null;
119-
}
91+
keyManager = new AdvancedTlsX509KeyManager();
92+
tlsChannelCredsBuilder.keyManager(keyManager);
12093
} else if (certChainPath != null || privateKeyPath != null) {
12194
logger.log(Level.WARNING, "Certificate chain and private key must be both set or unset");
12295
return null;
12396
}
12497

125-
// if executor was initialized, add it to allocated resource list
126-
if (scheduledExecutorService != null) {
127-
resourcesBuilder.add(asCloseable(scheduledExecutorService));
128-
}
129-
13098
return ResourceAllocatingChannelCredentials.create(
131-
tlsChannelCredsBuilder.build(), resourcesBuilder.build());
132-
}
133-
134-
private static Closeable asCloseable(ScheduledExecutorService scheduledExecutorService) {
135-
return () -> scheduledExecutorService.shutdownNow();
99+
tlsChannelCredsBuilder.build(),
100+
new ResourcesSupplier(
101+
refreshIntervalSeconds,
102+
rootCertPath,
103+
trustManager,
104+
certChainPath,
105+
privateKeyPath,
106+
keyManager));
136107
}
137108

138109
@Override
@@ -150,6 +121,84 @@ public int priority() {
150121
return 5;
151122
}
152123

124+
private static final class ResourcesSupplier implements Supplier<ImmutableList<Closeable>> {
125+
private final long refreshIntervalSeconds;
126+
private final String rootCertPath;
127+
private final AdvancedTlsX509TrustManager trustManager;
128+
private final String certChainPath;
129+
private final String privateKeyPath;
130+
private final AdvancedTlsX509KeyManager keyManager;
131+
132+
ResourcesSupplier(
133+
long refreshIntervalSeconds,
134+
String rootCertPath,
135+
AdvancedTlsX509TrustManager trustManager,
136+
String certChainPath,
137+
String privateKeyPath,
138+
AdvancedTlsX509KeyManager keyManager) {
139+
this.refreshIntervalSeconds = refreshIntervalSeconds;
140+
this.rootCertPath = rootCertPath;
141+
this.trustManager = trustManager;
142+
this.certChainPath = certChainPath;
143+
this.privateKeyPath = privateKeyPath;
144+
this.keyManager = keyManager;
145+
}
146+
147+
@Override
148+
public ImmutableList<Closeable> get() {
149+
ImmutableList.Builder<Closeable> resourcesBuilder = ImmutableList.builder();
150+
151+
ScheduledExecutorService scheduledExecutorService =
152+
(trustManager != null || keyManager != null)
153+
? scheduledExecutorService = scheduledExecutorServiceFactory.create()
154+
: null;
155+
if (scheduledExecutorService != null) {
156+
resourcesBuilder.add(asCloseable(scheduledExecutorService));
157+
}
158+
159+
if (trustManager != null) {
160+
try {
161+
Closeable trustManagerFuture = trustManager.updateTrustCredentials(
162+
new File(rootCertPath),
163+
refreshIntervalSeconds,
164+
TimeUnit.SECONDS,
165+
scheduledExecutorService);
166+
resourcesBuilder.add(trustManagerFuture);
167+
} catch (Exception e) {
168+
cleanupResources(resourcesBuilder.build());
169+
throw new RuntimeException("Unable to read root certificates", e);
170+
}
171+
}
172+
173+
if (keyManager != null) {
174+
try {
175+
Closeable keyManagerFuture = keyManager.updateIdentityCredentials(
176+
new File(certChainPath),
177+
new File(privateKeyPath),
178+
refreshIntervalSeconds,
179+
TimeUnit.SECONDS,
180+
scheduledExecutorService);
181+
resourcesBuilder.add(keyManagerFuture);
182+
} catch (Exception e) {
183+
cleanupResources(resourcesBuilder.build());
184+
throw new RuntimeException("Unable to read certificate chain or private key", e);
185+
}
186+
}
187+
188+
return resourcesBuilder.build();
189+
}
190+
191+
private static Closeable asCloseable(ScheduledExecutorService scheduledExecutorService) {
192+
return () -> scheduledExecutorService.shutdownNow();
193+
}
194+
195+
private static void cleanupResources(ImmutableList<Closeable> resources) {
196+
for (Closeable resource : resources) {
197+
GrpcUtil.closeQuietly(resource);
198+
}
199+
}
200+
}
201+
153202
abstract static class ScheduledExecutorServiceFactory {
154203

155204
private static final ScheduledExecutorServiceFactory DEFAULT_INSTANCE =

0 commit comments

Comments
 (0)