-
Notifications
You must be signed in to change notification settings - Fork 105
feat: enable setting quota_project_id #1128
Changes from 2 commits
8e7b92f
c641572
cea6118
a157f44
1151fdc
c6b9d47
0a8d179
a63ffae
74541a5
6a56e6b
0e1e201
7f91763
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,8 @@ | |
import com.google.api.gax.core.NoCredentialsProvider; | ||
import com.google.api.gax.tracing.ApiTracerFactory; | ||
import com.google.api.gax.tracing.NoopApiTracerFactory; | ||
import com.google.auth.Credentials; | ||
import com.google.auth.oauth2.QuotaProjectIdProvider; | ||
import com.google.common.base.MoreObjects; | ||
import com.google.common.base.Preconditions; | ||
import java.io.IOException; | ||
|
@@ -60,13 +62,16 @@ | |
*/ | ||
public abstract class StubSettings<SettingsT extends StubSettings<SettingsT>> { | ||
|
||
static final String QUOTA_PROJECT_ID_HEADER_KEY = "x-google-user-project"; | ||
|
||
private final ExecutorProvider executorProvider; | ||
private final CredentialsProvider credentialsProvider; | ||
private final HeaderProvider headerProvider; | ||
private final HeaderProvider internalHeaderProvider; | ||
private final TransportChannelProvider transportChannelProvider; | ||
private final ApiClock clock; | ||
private final String endpoint; | ||
private final String quotaProjectID; | ||
@Nullable private final WatchdogProvider streamWatchdogProvider; | ||
@Nonnull private final Duration streamWatchdogCheckInterval; | ||
@Nonnull private final ApiTracerFactory tracerFactory; | ||
|
@@ -80,6 +85,7 @@ protected StubSettings(Builder builder) { | |
this.internalHeaderProvider = builder.internalHeaderProvider; | ||
this.clock = builder.clock; | ||
this.endpoint = builder.endpoint; | ||
this.quotaProjectID = builder.quotaProjectID; | ||
this.streamWatchdogProvider = builder.streamWatchdogProvider; | ||
this.streamWatchdogCheckInterval = builder.streamWatchdogCheckInterval; | ||
this.tracerFactory = builder.tracerFactory; | ||
|
@@ -115,6 +121,10 @@ public final String getEndpoint() { | |
return endpoint; | ||
} | ||
|
||
public final String getQuotaProjectID() { | ||
return quotaProjectID; | ||
} | ||
|
||
@BetaApi("The surface for streaming is not stable yet and may change in the future.") | ||
@Nullable | ||
public final WatchdogProvider getStreamWatchdogProvider() { | ||
|
@@ -146,6 +156,7 @@ public String toString() { | |
.add("internalHeaderProvider", internalHeaderProvider) | ||
.add("clock", clock) | ||
.add("endpoint", endpoint) | ||
.add("quotaProjectID", quotaProjectID) | ||
.add("streamWatchdogProvider", streamWatchdogProvider) | ||
.add("streamWatchdogCheckInterval", streamWatchdogCheckInterval) | ||
.add("tracerFactory", tracerFactory) | ||
|
@@ -164,6 +175,7 @@ public abstract static class Builder< | |
private TransportChannelProvider transportChannelProvider; | ||
private ApiClock clock; | ||
private String endpoint; | ||
private String quotaProjectID; | ||
@Nullable private WatchdogProvider streamWatchdogProvider; | ||
@Nonnull private Duration streamWatchdogCheckInterval; | ||
@Nonnull private ApiTracerFactory tracerFactory; | ||
|
@@ -177,11 +189,29 @@ protected Builder(StubSettings settings) { | |
this.internalHeaderProvider = settings.internalHeaderProvider; | ||
this.clock = settings.clock; | ||
this.endpoint = settings.endpoint; | ||
this.quotaProjectID = settings.quotaProjectID; | ||
this.streamWatchdogProvider = settings.streamWatchdogProvider; | ||
this.streamWatchdogCheckInterval = settings.streamWatchdogCheckInterval; | ||
this.tracerFactory = settings.tracerFactory; | ||
} | ||
|
||
/** Get Quota Project ID from Client Context * */ | ||
private static String getQuotaProjectIDFromClientContext(ClientContext clientContext) { | ||
if (clientContext.getQuotaProjectID() != null) { | ||
return clientContext.getQuotaProjectID(); | ||
} | ||
if (clientContext.getCredentials() instanceof QuotaProjectIdProvider) { | ||
return ((QuotaProjectIdProvider) clientContext.getCredentials()).getQuotaProjectId(); | ||
} | ||
if (clientContext.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | ||
return clientContext.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); | ||
} | ||
if (clientContext.getInternalHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the difference between headers and internal headers? And is it possible for quota project to come in on either one? Also, what is the use case for pulling it from the header? I think maybe it is not necessary to detect this (@broady ?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. quota project id can be gotten from header and internal header. double confirm with @chingor13 but I am not sure the use case. @broady There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe the internal header provider is reserved for gapic and handwritten layers to inject headers. The general header provider is to allow library users to specify arbitrary extra headers. It's not desired for library users to set the quota project via header provider, but previously that was the only mechanism for doing so. We should have an explicit strategy for how to handle that case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for clarifying. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems ok to support this then, for backwards compatibility. And also to ensure any quota project behavior stays consistent regardless of how it's set. |
||
return clientContext.getInternalHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); | ||
} | ||
return null; | ||
} | ||
|
||
protected Builder(ClientContext clientContext) { | ||
if (clientContext == null) { | ||
this.executorProvider = InstantiatingExecutorProvider.newBuilder().build(); | ||
|
@@ -191,6 +221,7 @@ protected Builder(ClientContext clientContext) { | |
this.internalHeaderProvider = new NoHeaderProvider(); | ||
this.clock = NanoClock.getDefaultClock(); | ||
this.endpoint = null; | ||
this.quotaProjectID = null; | ||
this.streamWatchdogProvider = InstantiatingWatchdogProvider.create(); | ||
this.streamWatchdogCheckInterval = Duration.ofSeconds(10); | ||
this.tracerFactory = NoopApiTracerFactory.getInstance(); | ||
|
@@ -208,6 +239,7 @@ protected Builder(ClientContext clientContext) { | |
FixedWatchdogProvider.create(clientContext.getStreamWatchdog()); | ||
this.streamWatchdogCheckInterval = clientContext.getStreamWatchdogCheckInterval(); | ||
this.tracerFactory = clientContext.getTracerFactory(); | ||
this.quotaProjectID = getQuotaProjectIDFromClientContext(clientContext); | ||
} | ||
} | ||
|
||
|
@@ -234,6 +266,14 @@ public B setExecutorProvider(ExecutorProvider executorProvider) { | |
/** Sets the CredentialsProvider to use for getting the credentials to make calls with. */ | ||
public B setCredentialsProvider(CredentialsProvider credentialsProvider) { | ||
this.credentialsProvider = Preconditions.checkNotNull(credentialsProvider); | ||
try { | ||
Credentials credentials = credentialsProvider.getCredentials(); | ||
if (this.quotaProjectID == null && credentials instanceof QuotaProjectIdProvider) { | ||
this.quotaProjectID = ((QuotaProjectIdProvider) credentials).getQuotaProjectId(); | ||
} | ||
} catch (IOException e) { | ||
System.out.println("fail to fetch credentials"); | ||
} | ||
return self(); | ||
} | ||
|
||
|
@@ -247,6 +287,10 @@ public B setCredentialsProvider(CredentialsProvider credentialsProvider) { | |
@BetaApi("The surface for customizing headers is not stable yet and may change in the future.") | ||
public B setHeaderProvider(HeaderProvider headerProvider) { | ||
this.headerProvider = headerProvider; | ||
if (this.quotaProjectID == null | ||
&& headerProvider.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | ||
this.quotaProjectID = headerProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); | ||
} | ||
return self(); | ||
} | ||
|
||
|
@@ -260,6 +304,10 @@ public B setHeaderProvider(HeaderProvider headerProvider) { | |
@BetaApi("The surface for customizing headers is not stable yet and may change in the future.") | ||
protected B setInternalHeaderProvider(HeaderProvider internalHeaderProvider) { | ||
this.internalHeaderProvider = internalHeaderProvider; | ||
if (this.quotaProjectID == null | ||
&& internalHeaderProvider.getHeaders().containsKey(QUOTA_PROJECT_ID_HEADER_KEY)) { | ||
this.quotaProjectID = internalHeaderProvider.getHeaders().get(QUOTA_PROJECT_ID_HEADER_KEY); | ||
} | ||
return self(); | ||
} | ||
|
||
|
@@ -298,6 +346,11 @@ public B setEndpoint(String endpoint) { | |
return self(); | ||
} | ||
|
||
public B setQuotaProjectID(String quotaProjectID) { | ||
this.quotaProjectID = quotaProjectID; | ||
return self(); | ||
} | ||
|
||
/** | ||
* Sets how often the {@link Watchdog} will check ongoing streaming RPCs. Defaults to 10 secs. | ||
* Use {@link Duration#ZERO} to disable. | ||
|
@@ -364,6 +417,11 @@ public String getEndpoint() { | |
return endpoint; | ||
} | ||
|
||
/** Gets the QuotaProjectID that was previously set on this Builder. */ | ||
public String getQuotaProjectID() { | ||
return quotaProjectID; | ||
} | ||
|
||
@BetaApi("The surface for streaming is not stable yet and may change in the future.") | ||
@Nonnull | ||
public Duration getStreamWatchdogCheckInterval() { | ||
|
@@ -396,6 +454,7 @@ public String toString() { | |
.add("internalHeaderProvider", internalHeaderProvider) | ||
.add("clock", clock) | ||
.add("endpoint", endpoint) | ||
.add("quotaProjectID", quotaProjectID) | ||
.add("streamWatchdogProvider", streamWatchdogProvider) | ||
.add("streamWatchdogCheckInterval", streamWatchdogCheckInterval) | ||
.add("tracerFactory", tracerFactory) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like we use
ID
in methods and variables, andId
in class names. Is this idiomatic?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ID
used in all methods and variables, which is really just my preference. I haven't find any guideline for naming.Let me know if any rule need to be follow here, I could make change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use
quotaProjectId
. See https://google.github.io/styleguide/javaguide.html#s5-namingThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will make change to
quotaProjectId