Skip to content

Commit

Permalink
fix: set header for quota project when possible
Browse files Browse the repository at this point in the history
This commit partially addresses #9454, in the case when the provider is
configured with both the user_project_override AND billing_project
setting, by setting a header in the LoadAndValidate function stage on
the HTTP client used by all handwritten resources.

Originally this commit used a Google API client ClientOption [1],
but unfortunately headers set by the Google API client's transport
implementation [2] aren't visible by the logging transport [3]. I
thought it would be better to include the header at a higher level in
order to aid with debugging in the future. If [4] is ever merged, moving
the logging transport _inside_ of the API client and switching to a
ClientOption for the header would probably be a better way.

Finally, this does not address having user_project_override set to true
without the billing_project setting, as that would require more logic to
determine which project the resource is referring to.

[1] https://pkg.go.dev/google.golang.org/api/option#WithQuotaProject
[2] https://github.com/googleapis/google-api-go-client/blob/3e2b6a25f224e301409d11443d464af92671d2f0/transport/http/dial.go#L86-L88
[3] https://github.com/hashicorp/terraform-provider-google/blob/0e315b07d9ed37bd884a1060c22681908d23f270/google/config.go#L373-L374
[4] googleapis/google-cloud-go#1962
  • Loading branch information
ericnorris committed Jul 29, 2021
1 parent dfd1466 commit a35fcd2
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 4 deletions.
14 changes: 11 additions & 3 deletions google/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,19 @@ func (c *Config) LoadAndValidate(ctx context.Context) error {

cleanCtx := context.WithValue(ctx, oauth2.HTTPClient, cleanhttp.DefaultClient())

// 1. MTLS TRANSPORT/CLIENT - sets up proper auth headers
client, _, err := transport.NewHTTPClient(cleanCtx, option.WithTokenSource(tokenSource))
// 0. ClientOption setup for HTTP client
clientOpts := []option.ClientOption{
// Set up authorization headers
option.WithTokenSource(tokenSource),
}

// 1. MTLS TRANSPORT/CLIENT
client, _, err := transport.NewHTTPClient(cleanCtx, clientOpts...)

if err != nil {
return err
}

// Userinfo is fetched before request logging is enabled to reduce additional noise.
err = c.logGoogleIdentities()
if err != nil {
Expand All @@ -381,7 +389,7 @@ func (c *Config) LoadAndValidate(ctx context.Context) error {

// 4. Header Transport - outer wrapper to inject additional headers we want to apply
// before making requests
headerTransport := newTransportWithHeaders(retryTransport)
headerTransport := newTransportWithHeaders(retryTransport, c)

// Set final transport value.
client.Transport = headerTransport
Expand Down
9 changes: 8 additions & 1 deletion google/header_transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,23 @@ type headerTransportLayer struct {
baseTransit http.RoundTripper
}

func newTransportWithHeaders(baseTransit http.RoundTripper) headerTransportLayer {
func newTransportWithHeaders(baseTransit http.RoundTripper, c *Config) headerTransportLayer {
if baseTransit == nil {
baseTransit = http.DefaultTransport
}

headers := make(http.Header)

if requestReason := os.Getenv("CLOUDSDK_CORE_REQUEST_REASON"); requestReason != "" {
headers.Set("X-Goog-Request-Reason", requestReason)
}

// Ensure $userProject is set for all HTTP requests using the client if specified by the provider config
// See https://cloud.google.com/apis/docs/system-parameters
if c.UserProjectOverride && c.BillingProject != "" {
headers.Set("X-Goog-User-Project", c.BillingProject)
}

return headerTransportLayer{Header: headers, baseTransit: baseTransit}
}

Expand Down

0 comments on commit a35fcd2

Please sign in to comment.