feat(storage): add user_project option#5490
feat(storage): add user_project option#5490joshuatants wants to merge 2 commits intogoogleapis:mainfrom
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5490 +/- ##
=======================================
Coverage 97.73% 97.73%
=======================================
Files 218 218
Lines 49043 49070 +27
=======================================
+ Hits 47932 47961 +29
+ Misses 1111 1109 -2 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hi @googleapis/cloud-sdk-rust-team in this PR I add functionality to
Thank you for the advice. |
The tests are failing because there is new logic in The tests should pass if you bump the ... as well as the minimum version of Line 473 in 562640d The change is purely additive, so make the version (The same would have been true for adding a public API to |
I would prefer if we split these changes to |
dbolduc
left a comment
There was a problem hiding this comment.
Split this PR into two
This is typically a good idea. I would be grateful if you did this.
I did not look at the storage changes because I have enough feedback on the gax half.
| /// provider would have emitted from its configured `quota_project_id`, | ||
| /// so the wire carries exactly one `x-goog-user-project`. | ||
| #[derive(Debug, Clone, PartialEq)] | ||
| pub struct UserProject(http::HeaderValue); |
There was a problem hiding this comment.
I don't want to plumb this via the extensions. Can you just add a field + setters/getters similar to user_agent, user_agent(), set_user_agent(), with_user_agent() ?
| /// # Panics | ||
| /// | ||
| /// Panics if the project ID contains non-visible ASCII characters. |
There was a problem hiding this comment.
This is valid, but not customary for us. I think we can avoid it if we treat it like a user agent. The error may be less helpful, but eh.
| unreachable!("headers are not cached"); | ||
| }; | ||
|
|
||
| if let Some(up) = options.get_extension::<UserProject>() { |
There was a problem hiding this comment.
Meh, don't love that this is here. But it's fine.
If we keep this, can you add a comment like:
// The client-supplied user project must override the credential's user project. So we insert it after setting the credential's headers.
But I think I would prefer is to add this logic to Self::make_headers()
And then we just flip this to:
// Note that client headers override credential headers (e.g. for the `x-goog-user-project`).
data.extend(headers);
Ok(data)| if let Some(up) = options.get_extension::<UserProject>() { | ||
| data.insert(X_GOOG_USER_PROJECT, up.as_value().clone()); | ||
| } | ||
| builder.headers(data) |
There was a problem hiding this comment.
The logic doesn't belong in the match statement. Add a block like the user agent block right after this.
There was a problem hiding this comment.
Note that you need to use the builder.headers() method to insert the key and overwrite the previous entry. builder.header() is an append 🫨
optional: at this point, we might want to construct a http::HeaderMap and call builder.headers() once. 🤷
| } | ||
| Ok(CacheableResource::NotModified) => unreachable!("headers are not cached"), | ||
| }; | ||
| builder.build().map_err(map_send_error) |
There was a problem hiding this comment.
same as @dbolduc, I think we should add a method to the builder to allow overriding request level quota/user project. And maybe some similar code can be used in the gRPC part.
builder = quota_project(options)
.into_iter()
.fold(builder, |b, qp| b.header(X_GOOG_USER_PROJECT, qp));
fn quota_project(options: &crate::options::RequestOptions){
options.get_extension::<UserProject>()
}|
Thank you all for the feedback. Will split the PR and address the comments. ETA for the |
3cb6db2 to
521ba73
Compare
Adds a `with_user_project` method to `Storage` and `StorageControl` request builders to support Requester Pays buckets. When set, the internal gRPC and HTTP transports emit an `x-goog-user-project` header which takes precedence over any `quota_project_id` configured in the client credentials.
142e614 to
26d351c
Compare
26d351c to
3a8efbc
Compare
|
@dbolduc @alvarowolfx I've split the PR into two and kept only the
|
|
@joshuatants - Sorry, you're right. I offered a bad suggestion.
It is going to be a tough fix. Let me think about it for a bit and get back to you with a plan.
Yep. This was my mistake. At the time I thought I could make "breaking changes" such as adding a new trait function to public types marked as |
Actually, I found an easy fix, and wrote it up in go/cloud-rust:adding-request-options Basically, I think we can provide a default implementation for any new So we would say like: pub trait RequestOptionsBuilder : internal::RequestBuilder {
// <current fns omitted...>
fn with_user_project<V: Into<String>>(self, _v: V) -> Self
where Self: Sized { self }
}instead of: pub trait RequestOptionsBuilder : internal::RequestBuilder {
// <current fns omitted...>
fn with_user_project<V: Into<String>>(self, v: V) -> Self;
}... but maybe hold off on making changes in this PR until that doc gets approved. My team often thinks of things that I missed. |
|
Thanks for the help, will wait for updates. |
Adds a
with_user_projectmethod toStorageandStorageControlrequest builders to support Requester Pays buckets. When set, the internal gRPC and HTTP transports emit anx-goog-user-projectheader which takes precedence over anyquota_project_idconfigured in the client credentials.For #3189 and #3306.