@@ -168,52 +168,56 @@ func dial(ctx context.Context, insecure bool, o *internal.DialSettings) (*grpc.C
168
168
// when dialing an insecure connection?
169
169
if ! o .NoAuth && ! insecure {
170
170
if o .APIKey != "" {
171
- log .Print ("API keys are not supported for gRPC APIs. Remove the WithAPIKey option from your client-creating call." )
172
- }
173
- creds , err := internal .Creds (ctx , o )
174
- if err != nil {
175
- return nil , err
176
- }
177
-
178
- grpcOpts = append (grpcOpts ,
179
- grpc .WithPerRPCCredentials (grpcTokenSource {
180
- TokenSource : oauth.TokenSource {creds .TokenSource },
181
- quotaProject : internal .GetQuotaProject (creds , o .QuotaProject ),
171
+ grpcOpts = append (grpcOpts , grpc .WithPerRPCCredentials (grpcAPIKey {
172
+ apiKey : o .APIKey ,
182
173
requestReason : o .RequestReason ,
183
- }),
184
- )
185
-
186
- // Attempt Direct Path:
187
- logRateLimiter .Do (func () {
188
- logDirectPathMisconfig (endpoint , creds .TokenSource , o )
189
- })
190
- if isDirectPathEnabled (endpoint , o ) && isTokenSourceDirectPathCompatible (creds .TokenSource , o ) && metadata .OnGCE () {
191
- // Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
192
- grpcOpts = []grpc.DialOption {
193
- grpc .WithCredentialsBundle (grpcgoogle .NewDefaultCredentialsWithOptions (grpcgoogle.DefaultCredentialsOptions {oauth.TokenSource {creds .TokenSource }}))}
194
- if timeoutDialerOption != nil {
195
- grpcOpts = append (grpcOpts , timeoutDialerOption )
174
+ }))
175
+ } else {
176
+ creds , err := internal .Creds (ctx , o )
177
+ if err != nil {
178
+ return nil , err
196
179
}
197
- // Check if google-c2p resolver is enabled for DirectPath
198
- if isDirectPathXdsUsed (o ) {
199
- // google-c2p resolver target must not have a port number
200
- if addr , _ , err := net .SplitHostPort (endpoint ); err == nil {
201
- endpoint = "google-c2p:///" + addr
202
- } else {
203
- endpoint = "google-c2p:///" + endpoint
180
+ grpcOpts = append (grpcOpts , grpc .WithPerRPCCredentials (grpcTokenSource {
181
+ TokenSource : oauth.TokenSource {TokenSource : creds .TokenSource },
182
+ quotaProject : internal .GetQuotaProject (creds , o .QuotaProject ),
183
+ requestReason : o .RequestReason ,
184
+ }))
185
+ // Attempt Direct Path:
186
+ logRateLimiter .Do (func () {
187
+ logDirectPathMisconfig (endpoint , creds .TokenSource , o )
188
+ })
189
+ if isDirectPathEnabled (endpoint , o ) && isTokenSourceDirectPathCompatible (creds .TokenSource , o ) && metadata .OnGCE () {
190
+ // Overwrite all of the previously specific DialOptions, DirectPath uses its own set of credentials and certificates.
191
+ grpcOpts = []grpc.DialOption {
192
+ grpc .WithCredentialsBundle (grpcgoogle .NewDefaultCredentialsWithOptions (
193
+ grpcgoogle.DefaultCredentialsOptions {
194
+ PerRPCCreds : oauth.TokenSource {TokenSource : creds .TokenSource },
195
+ })),
204
196
}
205
- } else {
206
- if ! strings .HasPrefix (endpoint , "dns:///" ) {
207
- endpoint = "dns:///" + endpoint
197
+ if timeoutDialerOption != nil {
198
+ grpcOpts = append (grpcOpts , timeoutDialerOption )
208
199
}
209
- grpcOpts = append (grpcOpts ,
210
- // For now all DirectPath go clients will be using the following lb config, but in future
211
- // when different services need different configs, then we should change this to a
212
- // per-service config.
213
- grpc .WithDisableServiceConfig (),
214
- grpc .WithDefaultServiceConfig (`{"loadBalancingConfig":[{"grpclb":{"childPolicy":[{"pick_first":{}}]}}]}` ))
200
+ // Check if google-c2p resolver is enabled for DirectPath
201
+ if isDirectPathXdsUsed (o ) {
202
+ // google-c2p resolver target must not have a port number
203
+ if addr , _ , err := net .SplitHostPort (endpoint ); err == nil {
204
+ endpoint = "google-c2p:///" + addr
205
+ } else {
206
+ endpoint = "google-c2p:///" + endpoint
207
+ }
208
+ } else {
209
+ if ! strings .HasPrefix (endpoint , "dns:///" ) {
210
+ endpoint = "dns:///" + endpoint
211
+ }
212
+ grpcOpts = append (grpcOpts ,
213
+ // For now all DirectPath go clients will be using the following lb config, but in future
214
+ // when different services need different configs, then we should change this to a
215
+ // per-service config.
216
+ grpc .WithDisableServiceConfig (),
217
+ grpc .WithDefaultServiceConfig (`{"loadBalancingConfig":[{"grpclb":{"childPolicy":[{"pick_first":{}}]}}]}` ))
218
+ }
219
+ // TODO(cbro): add support for system parameters (quota project, request reason) via chained interceptor.
215
220
}
216
- // TODO(cbro): add support for system parameters (quota project, request reason) via chained interceptor.
217
221
}
218
222
}
219
223
@@ -271,6 +275,31 @@ func (ts grpcTokenSource) GetRequestMetadata(ctx context.Context, uri ...string)
271
275
return metadata , nil
272
276
}
273
277
278
+ // grpcAPIKey supplies PerRPCCredentials from an API Key.
279
+ type grpcAPIKey struct {
280
+ apiKey string
281
+
282
+ // Additional metadata attached as headers.
283
+ requestReason string
284
+ }
285
+
286
+ // GetRequestMetadata gets the request metadata as a map from a grpcAPIKey.
287
+ func (ts grpcAPIKey ) GetRequestMetadata (ctx context.Context , uri ... string ) (
288
+ map [string ]string , error ) {
289
+ metadata := map [string ]string {
290
+ "X-goog-api-key" : ts .apiKey ,
291
+ }
292
+ if ts .requestReason != "" {
293
+ metadata ["X-goog-request-reason" ] = ts .requestReason
294
+ }
295
+ return metadata , nil
296
+ }
297
+
298
+ // RequireTransportSecurity indicates whether the credentials requires transport security.
299
+ func (ts grpcAPIKey ) RequireTransportSecurity () bool {
300
+ return true
301
+ }
302
+
274
303
func isDirectPathEnabled (endpoint string , o * internal.DialSettings ) bool {
275
304
if ! o .EnableDirectPath {
276
305
return false
0 commit comments