-
-
Notifications
You must be signed in to change notification settings - Fork 301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Config
: make cluster/users/clusters optional
#1120
Conversation
Signed-off-by: goenning <me@goenning.net>
0da4e80
to
09a1d2e
Compare
Note: I'm still doing some ad-hoc tests on this, but I wanted to raise this for some early feedback/review. |
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## main #1120 +/- ##
==========================================
+ Coverage 72.63% 72.70% +0.07%
==========================================
Files 65 65
Lines 4867 4877 +10
==========================================
+ Hits 3535 3546 +11
+ Misses 1332 1331 -1
|
6771542
to
44a3279
Compare
Config
: make cluster/users/clusters optional
@clux I was doing a few more tests with this and it seems like the current solution doesn't work if the value as empty like this:
But it works if |
Ah, yeah that is different. The serde default does not happen in that case, because you are technically setting We would need something like https://docs.rs/serde_with/latest/serde_with/struct.DefaultOnNull.html to handle this. Does something actually generate |
It's not the case of being generated with null, but the user manually modified the file and it worked fine kubectl, but not on apps using kube-rs |
Well, I guess this brings us back to the previous discussion on this, where However, we did not really consider that it would be cause different parsing behaviour from kubectl by taking this route, and the go world ultimately dictates the serialisation format here. Maybe we should use DefaultOnNull after all for these cases 🤔 |
Either that or The way go handles deserialisation is a lot more forgiving, which is specially useful when these files can be manually modified. |
Yeah, I guess we should do |
Before I go ahead and work on this, should we do it on all fields that are currently |
It's hard to give a blanket answer here because it looks to me like it's context dependent. For instance, the conventions in the top config struct is different between similar fields: https://github.com/kubernetes/client-go/blob/228b004f4a926d43f53c0f8b6de3e1e2a3e50fcb/tools/clientcmd/api/types.go#L25-L54 Specifically: // 1.struct, not `+optional` marked, but still is optional. ours is `Option<Preferences>`
// ...theirs might just have an implied default (all the fields of the struct is +optional)
Preferences Preferences `json:"preferences"`
// 2. map with pointer to cluster.. so `clusters: ~` should not be allowed as it looks illegal with yaml.
// ..i would be surprised if we needed DefaultOnNull here, but it shouldn't make a huge difference
// in our case they are all vecs, with `#[serde(default, skip_serializing_if = "Vec::is_empty")]` prefix
Clusters map[string]*Cluster `json:"clusters"`
AuthInfos map[string]*AuthInfo `json:"users"`
Contexts map[string]*Context `json:"contexts"`
// 3. this one has to exist, but it's nice for us to have option wrapped for merge alg
CurrentContext string `json:"current-context"`
// 4. explicit +optional and omitempty map. `DefaultOnNull` and Option wrapped probably makes sense here
// +optional
Extensions map[string]runtime.Object `json:"extensions,omitempty"` Note the comment:
1 and 2 are probably fine to add Note this is only for the top level structs. How deep we want to follow this approach needs to be dictated by Such behaviour would mean making our kube/kube-client/src/config/file_config.rs Lines 409 to 439 in e0a4e49
So it's worth doing some testing and checking upstream how client-go merges configs before adding |
Thanks, I'll do some testing and compare the behavior between both libs and open an issue before doing any change. I think what can be confusing here is that But I'm actually surprised to see clusters/contexts/users as a map instead of an array, how the hell does that work? Unless they have a custom deserializer somewhere. |
Just remember that we should align with client-go and not kubectl.
Those are arrays in The link in https://github.com/kubernetes/client-go/blob/7697067af71046b18e03dbda04e01a5bb17f9809/tools/clientcmd/api/v1/conversion.go#L28 converts an array of named clusters to a map. https://github.com/kubernetes/client-go/blob/7697067af71046b18e03dbda04e01a5bb17f9809/tools/clientcmd/loader.go seems to be where it reads the file and deserializes the struct. |
Ah, interesting. So client-go effectively has a way to distinguish between more ergonomic types after conversion, and a disk format. ..It could similarly make sense to have a lax "pre-merge Kubeconfig" struct that is more option heavy, that is later converted into one where we have all properties (and invariants baked into errors returned by merge / conversion), plus convenience getters for map-style vectors. That would solve the ergonomics issues with options when we know the properties are required. That's more work though, and requires some care in terms of breaking changes. |
Motivation
This is a follow up on the previous work to make kube-rs parse kubeconfigs like client-go: #1076
We found another scenario where client-go allows us to have config files without clusters/users/contexts, while kube-rs does not. This mean a user could have all contexts/clusters in file A and keep users on file B.
Solution
Turn clusters/users/contexts into
Option<Vec<T>>