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
update fake dynamic client to return GVK #96020
Conversation
Today the dynamic fake client is not aware of *List kinds, so List calls return UnstructuredList objects without TypeMeta. This patch updates client-go's fake object tracker to store a map of GVR to list GVKs. In this way, the list GVK can be set for UnstructuredList objects. Signed-off-by: Andrew Sy Kim <kim.andrewsy@gmail.com>
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: deads2k The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/assign @yliaog |
return NewSimpleDynamicClientWithCustomResourceMapping(scheme, nil, objects...) | ||
} | ||
|
||
// NewSimpleDynamicClientWithCustomResourceMapping try not o use this. In general you want to have the scheme have the List types registered |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo, try no o use -> try not to use
@@ -799,7 +810,7 @@ func TestWaitForDeletionIgnoreNotFound(t *testing.T) { | |||
Namespace: "ns-foo", | |||
}, | |||
} | |||
fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme) | |||
fakeClient := dynamicfakeclient.NewSimpleDynamicClientWithCustomResourceMapping(scheme, listMapping) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this necessary? could you keep using NewSimpleDynamicClient(scheme) here and in other call sites above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this necessary? could you keep using NewSimpleDynamicClient(scheme) here and in other call sites above?
I can't because the existing tests separate resources and versions with unguessable names. I have to provide the mapping somehow and schemes don't allow it. I'm not sure how many other locations will face the same issue. Plurals in english are weird (and that's just english), so I think this is needed to provide people a path to upgrade.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. the other way is to make it always guessable, which means changing the guess function if/when necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. the other way is to make it always guessable, which means changing the guess function if/when necessary.
external components (imagine you have a custom operator) cannot modify that code.
return NewSimpleDynamicClientWithCustomResourceMapping(scheme, nil, objects...) | ||
} | ||
|
||
// NewSimpleDynamicClientWithCustomResourceMapping try not o use this. In general you want to have the scheme have the List types registered |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: s/o/to
|
||
// NewSimpleDynamicClientWithCustomResourceMapping try not o use this. In general you want to have the scheme have the List types registered | ||
// and allow the default guessing for resources match. Sometimes that doesn't work, so you can specify a custom mapping here. | ||
func NewSimpleDynamicClientWithCustomResourceMapping(scheme *runtime.Scheme, gvrToListKind map[schema.GroupVersionResource]string, objects ...runtime.Object) *FakeDynamicClient { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be helpful to be explicit about List kinds and name this NewSimpleDynamicClientWithCustomListKinds
if cm.GetObjectKind().GroupVersionKind() != (schema.GroupVersionKind{}) { | ||
t.Fatal(cm.GetObjectKind().GroupVersionKind()) | ||
} | ||
cmList, err := fakeKubeClient.CoreV1().ConfigMaps("foo-ns").Get(context.TODO(), "foo-name", metav1.GetOptions{}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing this is supposed to call List and not Get
t.Fatal(err) | ||
} | ||
if cmList.GetObjectKind().GroupVersionKind() != (schema.GroupVersionKind{}) { | ||
t.Fatal(cm.GetObjectKind().GroupVersionKind()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/cm/cmList/
@@ -799,7 +810,7 @@ func TestWaitForDeletionIgnoreNotFound(t *testing.T) { | |||
Namespace: "ns-foo", | |||
}, | |||
} | |||
fakeClient := dynamicfakeclient.NewSimpleDynamicClient(scheme) | |||
fakeClient := dynamicfakeclient.NewSimpleDynamicClientWithCustomResourceMapping(scheme, listMapping) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok. the other way is to make it always guessable, which means changing the guess function if/when necessary.
In usage, if your resource has a plural that isn't guessable, then you couldn't use this client to test your actual resource. Imagine writing controllers that use dynamic clients to access |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was thinking about making the guess function extendable for such non-guessable cases. but no matter your current way or the other way, there must be a way to provide a mapping of non-guessable Kind -> list Kind. i'm fine with the current way. thanks.
"k8s.io/client-go/kubernetes/scheme" | ||
) | ||
|
||
// this test proves that the kube fake client does not return GVKs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a TODO comment, so readers know this is not desired, and should be fixed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a TODO comment, so readers know this is not desired, and should be fixed?
sure. I will clarify.
t.Fatal(cm.GetObjectKind().GroupVersionKind()) | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the following two tests are not about fake client, should the file name be renamed to something other than fake_client_test.go?
gvrToListKind := map[schema.GroupVersionResource]string{ | ||
{Group: "apps", Version: "v1", Resource: "deployments"}: "DeploymentList", | ||
} | ||
fakeClient := fake.NewSimpleDynamicClientWithCustomResourceMapping(scheme, gvrToListKind, objs...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, i'm a bit confused. 'deployments' -> 'DeploymentList' should be guessable, no? is the switch from NewSimpleDynamicClient to NewSimpleDynamicClientWithCustomResourceMapping here really necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, i'm a bit confused. 'deployments' -> 'DeploymentList' should be guessable, no? is the switch from NewSimpleDynamicClient to NewSimpleDynamicClientWithCustomResourceMapping here really necessary?
The scheme they choose to test with does not have the deployment listed. This test is specifically about whether dynamic resources (those without scheme entries) can be properly handled. This means that it is correct for the usage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clarifying in comments.
updated for comments and verify. Clarified several points in the code. |
I think it would be useful to include release notes for this bug fix. Not familiar enough with apimachinery to lgtm this so I'll defer that to someone else who is. |
/lgtm |
/retest Review the full test history for this PR. Silence the bot with an |
@deads2k can we cherry-pick this? |
Thanks @deads2k! |
Thanks to @andrewsykim for #95951, the test he added to make this obvious, and the action wiring itself.
I created a proof commit to show that generated clients do not return GVK for from their serialized bytes. Whether this is right or wrong is a problem for another day. In comparison, the dynamic client does return GVK information so that it can be interpreted by other layers. The fake dynamic client did not do this.
This PR keeps the fake generated clients as they are, loads a GVR to listGVK mapping in the dynamic client by doing an unsafe guess, and allows for overrides of specific resources to specific list GVK mappings. It also adds several panics to catch test behavior that needs updating (coding errors).
/kind bug
@kubernetes/sig-api-machinery-bugs
/assign @andrewsykim
/priority important-soon