|
32 | 32 | import com.google.api.core.ApiFunction; |
33 | 33 | import com.google.api.core.BetaApi; |
34 | 34 | import com.google.api.core.InternalApi; |
35 | | -import com.google.api.core.InternalExtensionOnly; |
36 | 35 | import com.google.api.gax.core.ExecutorProvider; |
37 | 36 | import com.google.api.gax.rpc.FixedHeaderProvider; |
38 | 37 | import com.google.api.gax.rpc.HeaderProvider; |
|
82 | 81 | * <p>The client lib header and generator header values are used to form a value that goes into the |
83 | 82 | * http header of requests to the service. |
84 | 83 | */ |
85 | | -@InternalExtensionOnly |
86 | 84 | public final class InstantiatingGrpcChannelProvider implements TransportChannelProvider { |
| 85 | + |
| 86 | + static String systemProductName; |
| 87 | + |
| 88 | + static { |
| 89 | + try { |
| 90 | + systemProductName = |
| 91 | + Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8) |
| 92 | + .readFirstLine(); |
| 93 | + } catch (IOException e) { |
| 94 | + // If not on Compute Engine, FileNotFoundException will be thrown. Use empty string |
| 95 | + // as it won't match with the GCE_PRODUCTION_NAME constants |
| 96 | + systemProductName = ""; |
| 97 | + } |
| 98 | + } |
| 99 | + |
87 | 100 | @VisibleForTesting |
88 | 101 | static final Logger LOG = Logger.getLogger(InstantiatingGrpcChannelProvider.class.getName()); |
89 | 102 |
|
90 | | - private static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = |
91 | | - "GOOGLE_CLOUD_DISABLE_DIRECT_PATH"; |
| 103 | + static final String DIRECT_PATH_ENV_DISABLE_DIRECT_PATH = "GOOGLE_CLOUD_DISABLE_DIRECT_PATH"; |
92 | 104 | private static final String DIRECT_PATH_ENV_ENABLE_XDS = "GOOGLE_CLOUD_ENABLE_DIRECT_PATH_XDS"; |
93 | 105 | static final long DIRECT_PATH_KEEP_ALIVE_TIME_SECONDS = 3600; |
94 | 106 | static final long DIRECT_PATH_KEEP_ALIVE_TIMEOUT_SECONDS = 20; |
@@ -147,6 +159,19 @@ private InstantiatingGrpcChannelProvider(Builder builder) { |
147 | 159 | : builder.directPathServiceConfig; |
148 | 160 | } |
149 | 161 |
|
| 162 | + /** |
| 163 | + * Package-Private constructor that is only visible for testing DirectPath functionality inside |
| 164 | + * tests. This overrides the computed systemProductName when the class is initialized to help |
| 165 | + * configure the result of {@link #isOnComputeEngine()} check. |
| 166 | + * |
| 167 | + * <p>If productName is null, that represents the result of an IOException |
| 168 | + */ |
| 169 | + @VisibleForTesting |
| 170 | + InstantiatingGrpcChannelProvider(Builder builder, String productName) { |
| 171 | + this(builder); |
| 172 | + systemProductName = productName; |
| 173 | + } |
| 174 | + |
150 | 175 | /** |
151 | 176 | * @deprecated If executor is not set, this channel provider will create channels with default |
152 | 177 | * grpc executor. |
@@ -257,8 +282,8 @@ private boolean isDirectPathEnabled() { |
257 | 282 | return false; |
258 | 283 | } |
259 | 284 |
|
260 | | - @VisibleForTesting |
261 | | - boolean isDirectPathXdsEnabled() { |
| 285 | + @InternalApi |
| 286 | + public boolean isDirectPathXdsEnabled() { |
262 | 287 | // Method 1: Enable DirectPath xDS by option. |
263 | 288 | if (Boolean.TRUE.equals(attemptDirectPathXds)) { |
264 | 289 | return true; |
@@ -320,15 +345,9 @@ boolean isCredentialDirectPathCompatible() { |
320 | 345 | static boolean isOnComputeEngine() { |
321 | 346 | String osName = System.getProperty("os.name"); |
322 | 347 | if ("Linux".equals(osName)) { |
323 | | - try { |
324 | | - String result = |
325 | | - Files.asCharSource(new File("/sys/class/dmi/id/product_name"), StandardCharsets.UTF_8) |
326 | | - .readFirstLine(); |
327 | | - return result.contains(GCE_PRODUCTION_NAME_PRIOR_2016) |
328 | | - || result.contains(GCE_PRODUCTION_NAME_AFTER_2016); |
329 | | - } catch (IOException ignored) { |
330 | | - return false; |
331 | | - } |
| 348 | + // systemProductName will be empty string if not on Compute Engine |
| 349 | + return systemProductName.contains(GCE_PRODUCTION_NAME_PRIOR_2016) |
| 350 | + || systemProductName.contains(GCE_PRODUCTION_NAME_AFTER_2016); |
332 | 351 | } |
333 | 352 | return false; |
334 | 353 | } |
@@ -370,10 +389,7 @@ private ManagedChannel createSingleChannel() throws IOException { |
370 | 389 |
|
371 | 390 | // Check DirectPath traffic. |
372 | 391 | boolean useDirectPathXds = false; |
373 | | - if (isDirectPathEnabled() |
374 | | - && isCredentialDirectPathCompatible() |
375 | | - && isOnComputeEngine() |
376 | | - && canUseDirectPathWithUniverseDomain()) { |
| 392 | + if (canUseDirectPath()) { |
377 | 393 | CallCredentials callCreds = MoreCallCredentials.from(credentials); |
378 | 394 | ChannelCredentials channelCreds = |
379 | 395 | GoogleDefaultChannelCredentials.newBuilder().callCredentials(callCreds).build(); |
@@ -446,6 +462,24 @@ && canUseDirectPathWithUniverseDomain()) { |
446 | 462 | return managedChannel; |
447 | 463 | } |
448 | 464 |
|
| 465 | + /** |
| 466 | + * Marked as Internal Api and intended for internal use. DirectPath must be enabled via the |
| 467 | + * settings and a few other configurations/settings must also be valid for the request to go |
| 468 | + * through DirectPath. |
| 469 | + * |
| 470 | + * <p>Checks: 1. Credentials are compatible 2.Running on Compute Engine 3. Universe Domain is |
| 471 | + * configured to for the Google Default Universe |
| 472 | + * |
| 473 | + * @return if DirectPath is enabled for the client AND if the configurations are valid |
| 474 | + */ |
| 475 | + @InternalApi |
| 476 | + public boolean canUseDirectPath() { |
| 477 | + return isDirectPathEnabled() |
| 478 | + && isCredentialDirectPathCompatible() |
| 479 | + && isOnComputeEngine() |
| 480 | + && canUseDirectPathWithUniverseDomain(); |
| 481 | + } |
| 482 | + |
449 | 483 | /** The endpoint to be used for the channel. */ |
450 | 484 | @Override |
451 | 485 | public String getEndpoint() { |
@@ -753,6 +787,12 @@ public Builder setAttemptDirectPathXds() { |
753 | 787 | return this; |
754 | 788 | } |
755 | 789 |
|
| 790 | + @VisibleForTesting |
| 791 | + Builder setEnvProvider(EnvironmentProvider envProvider) { |
| 792 | + this.envProvider = envProvider; |
| 793 | + return this; |
| 794 | + } |
| 795 | + |
756 | 796 | /** |
757 | 797 | * Sets a service config for direct path. If direct path is not enabled, the provided service |
758 | 798 | * config will be ignored. |
|
0 commit comments