• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #19747

21 Mar 2025 10:19PM UTC coverage: 88.583% (-0.02%) from 88.604%
#19747

push

github

web-flow
xds: add support for custom per-target credentials on the transport (#11951)

34606 of 39066 relevant lines covered (88.58%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.06
/../xds/src/main/java/io/grpc/xds/SharedXdsClientPoolProvider.java
1
/*
2
 * Copyright 2020 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import static com.google.common.base.Preconditions.checkNotNull;
20

21
import com.google.common.annotations.VisibleForTesting;
22
import com.google.common.collect.ImmutableList;
23
import com.google.errorprone.annotations.concurrent.GuardedBy;
24
import io.grpc.CallCredentials;
25
import io.grpc.MetricRecorder;
26
import io.grpc.internal.ExponentialBackoffPolicy;
27
import io.grpc.internal.GrpcUtil;
28
import io.grpc.internal.ObjectPool;
29
import io.grpc.internal.SharedResourceHolder;
30
import io.grpc.internal.TimeProvider;
31
import io.grpc.xds.client.Bootstrapper;
32
import io.grpc.xds.client.Bootstrapper.BootstrapInfo;
33
import io.grpc.xds.client.XdsClient;
34
import io.grpc.xds.client.XdsClientImpl;
35
import io.grpc.xds.client.XdsInitializationException;
36
import io.grpc.xds.internal.security.TlsContextManagerImpl;
37
import java.util.Map;
38
import java.util.concurrent.ConcurrentHashMap;
39
import java.util.concurrent.ScheduledExecutorService;
40
import java.util.concurrent.atomic.AtomicReference;
41
import java.util.logging.Level;
42
import java.util.logging.Logger;
43
import javax.annotation.Nullable;
44
import javax.annotation.concurrent.ThreadSafe;
45

46
/**
47
 * The global factory for creating a singleton {@link XdsClient} instance to be used by all gRPC
48
 * clients in the process.
49
 */
50
@ThreadSafe
51
final class SharedXdsClientPoolProvider implements XdsClientPoolFactory {
52
  private static final boolean LOG_XDS_NODE_ID = Boolean.parseBoolean(
1✔
53
      System.getenv("GRPC_LOG_XDS_NODE_ID"));
1✔
54
  private static final Logger log = Logger.getLogger(XdsClientImpl.class.getName());
1✔
55
  private static final ExponentialBackoffPolicy.Provider BACKOFF_POLICY_PROVIDER =
1✔
56
      new ExponentialBackoffPolicy.Provider();
57

58
  private final Bootstrapper bootstrapper;
59
  private final Object lock = new Object();
1✔
60
  private final AtomicReference<Map<String, ?>> bootstrapOverride = new AtomicReference<>();
1✔
61
  private final Map<String, ObjectPool<XdsClient>> targetToXdsClientMap = new ConcurrentHashMap<>();
1✔
62

63
  SharedXdsClientPoolProvider() {
64
    this(new GrpcBootstrapperImpl());
1✔
65
  }
1✔
66

67
  @VisibleForTesting
68
  SharedXdsClientPoolProvider(Bootstrapper bootstrapper) {
1✔
69
    this.bootstrapper = checkNotNull(bootstrapper, "bootstrapper");
1✔
70
  }
1✔
71

72
  static SharedXdsClientPoolProvider getDefaultProvider() {
73
    return SharedXdsClientPoolProviderHolder.instance;
1✔
74
  }
75

76
  @Override
77
  public void setBootstrapOverride(Map<String, ?> bootstrap) {
78
    bootstrapOverride.set(bootstrap);
1✔
79
  }
1✔
80

81
  @Override
82
  @Nullable
83
  public ObjectPool<XdsClient> get(String target) {
84
    return targetToXdsClientMap.get(target);
1✔
85
  }
86

87
  @Override
88
  public ObjectPool<XdsClient> getOrCreate(String target, MetricRecorder metricRecorder)
89
      throws XdsInitializationException {
90
    return getOrCreate(target, metricRecorder, null);
1✔
91
  }
92

93
  public ObjectPool<XdsClient> getOrCreate(
94
      String target, MetricRecorder metricRecorder, CallCredentials transportCallCredentials)
95
      throws XdsInitializationException {
96
    ObjectPool<XdsClient> ref = targetToXdsClientMap.get(target);
1✔
97
    if (ref == null) {
1✔
98
      synchronized (lock) {
1✔
99
        ref = targetToXdsClientMap.get(target);
1✔
100
        if (ref == null) {
1✔
101
          BootstrapInfo bootstrapInfo;
102
          Map<String, ?> rawBootstrap = bootstrapOverride.get();
1✔
103
          if (rawBootstrap != null) {
1✔
104
            bootstrapInfo = bootstrapper.bootstrap(rawBootstrap);
1✔
105
          } else {
106
            bootstrapInfo = bootstrapper.bootstrap();
1✔
107
          }
108
          if (bootstrapInfo.servers().isEmpty()) {
1✔
109
            throw new XdsInitializationException("No xDS server provided");
1✔
110
          }
111
          ref =
1✔
112
              new RefCountedXdsClientObjectPool(
113
                  bootstrapInfo, target, metricRecorder, transportCallCredentials);
114
          targetToXdsClientMap.put(target, ref);
1✔
115
        }
116
      }
1✔
117
    }
118
    return ref;
1✔
119
  }
120

121
  @Override
122
  public ImmutableList<String> getTargets() {
123
    return ImmutableList.copyOf(targetToXdsClientMap.keySet());
1✔
124
  }
125

126
  private static class SharedXdsClientPoolProviderHolder {
127
    private static final SharedXdsClientPoolProvider instance = new SharedXdsClientPoolProvider();
1✔
128
  }
129

130
  @ThreadSafe
131
  @VisibleForTesting
132
  class RefCountedXdsClientObjectPool implements ObjectPool<XdsClient> {
133

134
    private final BootstrapInfo bootstrapInfo;
135
    private final String target; // The target associated with the xDS client.
136
    private final MetricRecorder metricRecorder;
137
    private final CallCredentials transportCallCredentials;
138
    private final Object lock = new Object();
1✔
139
    @GuardedBy("lock")
140
    private ScheduledExecutorService scheduler;
141
    @GuardedBy("lock")
142
    private XdsClient xdsClient;
143
    @GuardedBy("lock")
144
    private int refCount;
145
    @GuardedBy("lock")
146
    private XdsClientMetricReporterImpl metricReporter;
147

148
    @VisibleForTesting
149
    RefCountedXdsClientObjectPool(
150
        BootstrapInfo bootstrapInfo, String target, MetricRecorder metricRecorder) {
151
      this(bootstrapInfo, target, metricRecorder, null);
1✔
152
    }
1✔
153

154
    @VisibleForTesting
155
    RefCountedXdsClientObjectPool(
156
        BootstrapInfo bootstrapInfo,
157
        String target,
158
        MetricRecorder metricRecorder,
159
        CallCredentials transportCallCredentials) {
1✔
160
      this.bootstrapInfo = checkNotNull(bootstrapInfo);
1✔
161
      this.target = target;
1✔
162
      this.metricRecorder = metricRecorder;
1✔
163
      this.transportCallCredentials = transportCallCredentials;
1✔
164
    }
1✔
165

166
    @Override
167
    public XdsClient getObject() {
168
      synchronized (lock) {
1✔
169
        if (refCount == 0) {
1✔
170
          if (LOG_XDS_NODE_ID) {
1✔
171
            log.log(Level.INFO, "xDS node ID: {0}", bootstrapInfo.node().getId());
×
172
          }
173
          scheduler = SharedResourceHolder.get(GrpcUtil.TIMER_SERVICE);
1✔
174
          metricReporter = new XdsClientMetricReporterImpl(metricRecorder, target);
1✔
175
          GrpcXdsTransportFactory xdsTransportFactory =
1✔
176
              new GrpcXdsTransportFactory(transportCallCredentials);
177
          xdsClient =
1✔
178
              new XdsClientImpl(
179
                  xdsTransportFactory,
180
                  bootstrapInfo,
181
                  scheduler,
182
                  BACKOFF_POLICY_PROVIDER,
1✔
183
                  GrpcUtil.STOPWATCH_SUPPLIER,
184
                  TimeProvider.SYSTEM_TIME_PROVIDER,
185
                  MessagePrinter.INSTANCE,
186
                  new TlsContextManagerImpl(bootstrapInfo),
187
                  metricReporter);
188
          metricReporter.setXdsClient(xdsClient);
1✔
189
        }
190
        refCount++;
1✔
191
        return xdsClient;
1✔
192
      }
193
    }
194

195
    @Override
196
    public XdsClient returnObject(Object object) {
197
      synchronized (lock) {
1✔
198
        refCount--;
1✔
199
        if (refCount == 0) {
1✔
200
          xdsClient.shutdown();
1✔
201
          xdsClient = null;
1✔
202
          metricReporter.close();
1✔
203
          metricReporter = null;
1✔
204
          targetToXdsClientMap.remove(target);
1✔
205
          scheduler = SharedResourceHolder.release(GrpcUtil.TIMER_SERVICE, scheduler);
1✔
206
        }
207
        return null;
1✔
208
      }
209
    }
210

211
    @VisibleForTesting
212
    @Nullable
213
    XdsClient getXdsClientForTest() {
214
      synchronized (lock) {
1✔
215
        return xdsClient;
1✔
216
      }
217
    }
218

219
    public String getTarget() {
220
      return target;
×
221
    }
222
  }
223

224
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc