Api<PartialObjectMeta<K>> should opportunistically degrade to metadata requests#1952
Conversation
Add `fn metadata_api() -> bool` to the `Resource` trait (default false), overridden to return true for `PartialObjectMeta<K>`. This allows downstream code to detect metadata-only types at compile time and automatically switch to efficient metadata-optimized API requests. Ref: kube-rs#1614 Signed-off-by: doxxx93 <doxxx93@gmail.com>
Api methods get, list, watch, and patch now branch on Resource::metadata_api() to automatically use metadata-optimized Accept headers when K = PartialObjectMeta<_>, so the API server returns only metadata instead of the full object. Ref: kube-rs#1614 Signed-off-by: doxxx93 <doxxx93@gmail.com>
With Api<PartialObjectMeta<K>> now automatically using metadata-only requests, metadata_watcher is no longer needed. Users can use watcher(Api::<PartialObjectMeta<K>>::all(client), config) instead. Simplify the dynamic_watcher example to remove the runtime branching and focus on dynamic resource watching. Ref: kube-rs#1614 Signed-off-by: doxxx93 <doxxx93@gmail.com>
Add mock-based tests verifying that Api<PartialObjectMeta<Pod>> sends the correct metadata-only Accept headers for get, list, watch, and patch operations. Ref: kube-rs#1614 Signed-off-by: doxxx93 <doxxx93@gmail.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1952 +/- ##
=======================================
+ Coverage 75.6% 75.8% +0.2%
=======================================
Files 89 89
Lines 8666 8745 +79
=======================================
+ Hits 6544 6621 +77
- Misses 2122 2124 +2
🚀 New features to boost your workflow:
|
clux
left a comment
There was a problem hiding this comment.
This is a great idea. Simplifies watcher complexity a bit and lits the logic into kube-core which is always great to see.
It is a breaking change so one for the next major, but i like this a lot.
| impl<K> ApiMode for FullObject<'_, K> | ||
| where | ||
| K: Clone + Debug + DeserializeOwned + Send + 'static, | ||
| K: Resource + Clone + Debug + DeserializeOwned + Send + 'static, |
There was a problem hiding this comment.
Looking a bit more around, I am noticing that this technically breaks the intention of the Lookup trait introduced in #1393 since now special user types (described in #1389 ) have to impl Resource anyway.
Maybe we should also extend Lookup to be able to determine if it's a metadata_api type (with a default impl), and maybe we could rely on Lookup as the watcher constraint instead since it is lighter than full Resource?
There was a problem hiding this comment.
sorry for late reply I'll check it tmrw and update it
There was a problem hiding this comment.
Sorry for the long delay!
Digging into where the K: Resource actually crept in: it was really just one line in core_methods.rs (calling K::metadata_api() per request), which then forced the same bound onto both ApiMode impls in watcher.rs.
So the fix is to cache metadata_api on Api<K> itself, populated in the existing impl<K: Resource> Api<K> constructors where the bound was already required. The per-method paths just read self.metadata_api now, and I could drop all three Resource additions. No method bound is tighter than before this PR.
On extending Lookup with metadata_api() and switching the watcher to a Lookup bound: I'd love to do it but it feels like a bigger refactor than this PR should swallow. Api<K> itself needs K: Resource for URL building, and watcher takes Api<K>, so even with the flag on Lookup a Lookup-only K can't reach the watcher path today. The reflector::Store Lookup relaxation from #1393 still works for the #1389 use case (they bring their own watch source).
Happy to open a follow-up issue for "loosen watcher's data source so Lookup-only K can use it" if that's a direction you want to keep alive. Or if you'd rather have Lookup::metadata_api() default-imp landed here too as a pure declarative move, just say the word and I'll add it.
There was a problem hiding this comment.
Very nice. I agree you don't you need to extend Lookup as it is already quite custom. I just don't want it to be completely incompatible with even the Api.
Notifying @SOF3 as a heads up about this change though.
PR review feedback (clux): the original PR added `K: Resource` to `impl<K> Api<K>` in core_methods.rs (so it could call `K::metadata_api()` per request), which forced the same bound onto `ApiMode for FullObject<K>` and `ApiMode for MetaOnly<K>` in watcher.rs. This goes against the spirit of kube-rs#1393 by tightening method-level bounds beyond what the corresponding Api/watcher constructors already require. Cache the flag on `Api<K>` itself in the existing `impl<K: Resource> Api<K>` constructors, then read `self.metadata_api` from the per-method code paths. The Resource bound stays exactly where it was before this PR (Api constructors and the public `watcher`/`metadata_watcher` signatures), no user-visible API change. See kube-rs#1952 (comment)
PR review feedback (clux): the original PR added `K: Resource` to `impl<K> Api<K>` in core_methods.rs (so it could call `K::metadata_api()` per request), which forced the same bound onto `ApiMode for FullObject<K>` and `ApiMode for MetaOnly<K>` in watcher.rs. This goes against the spirit of kube-rs#1393 by tightening method-level bounds beyond what the corresponding Api/watcher constructors already require. Cache the flag on `Api<K>` itself in the existing `impl<K: Resource> Api<K>` constructors, then read `self.metadata_api` from the per-method code paths. The Resource bound stays exactly where it was before this PR (Api constructors and the public `watcher`/`metadata_watcher` signatures), no user-visible API change. See kube-rs#1952 (comment) Signed-off-by: doxxx93 <doxxx93@gmail.com>
5794bc0 to
813f93f
Compare
|
Did some quick associated doc updates in kube-rs/website#95 as a sanity check to myself. A slight downside of the deprecation here is that users do have to bring |
Motivation
Currently
Api<PartialObjectMeta<K>>::get(and list, watch, patch) requests the wholeobject from the API server and discards everything except metadata during deserialization.
This requires every downstream API to maintain separate metadata variants (e.g.
metadata_watcher, andController::watcheshas no metadata path at all).Solution
Add
fn metadata_api() -> boolto theResourcetrait (defaultfalse), overridden totrueforPartialObjectMeta<K>. Api methodsget,list,watch, andpatchbranchon this flag to automatically use metadata-optimized Accept headers.
metadata_api()toResourcetrait with doctestK::metadata_api()metadata_watcherin favor ofwatcher(Api::<PartialObjectMeta<K>>::all(client), config)Closes #1614