From 0976267f0f4c27cd61cd88041d68d3465a8f9d86 Mon Sep 17 00:00:00 2001 From: Andy Goldstein Date: Tue, 18 Oct 2022 16:34:28 -0400 Subject: [PATCH] Make empty unstructured check common Move the empty unstructured object check from the webhook converter to the delegating converter, so other converters don't have to repeat the same logic. Signed-off-by: Andy Goldstein --- .../pkg/apiserver/conversion/converter.go | 27 ++++++++++++++++++ .../apiserver/conversion/webhook_converter.go | 28 ------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/converter.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/converter.go index aafe44f87c3..89600d1b6fb 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/converter.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/converter.go @@ -179,6 +179,7 @@ func (c *delegatingCRConverter) ConvertToVersion(in runtime.Object, target runti // TODO: should this be a typed error? return nil, fmt.Errorf("%v is unstructured and is not suitable for converting to %q", fromGVK.String(), target) } + // Special-case typed scale conversion if this custom resource supports a scale endpoint if c.convertScale { if _, isInScale := in.(*autoscalingv1.Scale); isInScale { @@ -204,6 +205,13 @@ func (c *delegatingCRConverter) ConvertToVersion(in runtime.Object, target runti } } } + + // A smoke test in API machinery calls the converter on empty objects during startup. The test is initiated here: + // https://github.com/kubernetes/kubernetes/blob/dbb448bbdcb9e440eee57024ffa5f1698956a054/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher.go#L201 + if isEmptyUnstructuredObject(in) { + return NewNOPConverter().Convert(in, toGVK.GroupVersion()) + } + return c.converter.Convert(in, toGVK.GroupVersion()) } @@ -232,3 +240,22 @@ func (c *safeConverterWrapper) Convert(in, out, context interface{}) error { func (c *safeConverterWrapper) ConvertToVersion(in runtime.Object, target runtime.GroupVersioner) (runtime.Object, error) { return c.unsafe.ConvertToVersion(in.DeepCopyObject(), target) } + +// isEmptyUnstructuredObject returns true if in is an empty unstructured object, i.e. an unstructured object that does +// not have any field except apiVersion and kind. +func isEmptyUnstructuredObject(in runtime.Object) bool { + u, ok := in.(*unstructured.Unstructured) + if !ok { + return false + } + if len(u.Object) != 2 { + return false + } + if _, ok := u.Object["kind"]; !ok { + return false + } + if _, ok := u.Object["apiVersion"]; !ok { + return false + } + return true +} diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/webhook_converter.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/webhook_converter.go index 3cb05cef5b4..f89cf448de6 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/webhook_converter.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/apiserver/conversion/webhook_converter.go @@ -229,15 +229,6 @@ func getConvertedObjectsFromResponse(expectedUID types.UID, response runtime.Obj func (c *webhookConverter) Convert(in runtime.Object, toGV schema.GroupVersion) (runtime.Object, error) { ctx := context.TODO() - // In general, the webhook should not do any defaulting or validation. A special case of that is an empty object - // conversion that must result an empty object and practically is the same as nopConverter. - // A smoke test in API machinery calls the converter on empty objects. As this case happens consistently - // it special cased here not to call webhook converter. The test initiated here: - // https://github.com/kubernetes/kubernetes/blob/dbb448bbdcb9e440eee57024ffa5f1698956a054/staging/src/k8s.io/apiserver/pkg/storage/cacher/cacher.go#L201 - if isEmptyUnstructuredObject(in) { - return c.nopConverter.Convert(in, toGV) - } - listObj, isList := in.(*unstructured.UnstructuredList) requestUID := uuid.NewUUID() @@ -451,22 +442,3 @@ func restoreObjectMeta(original, converted *unstructured.Unstructured) error { return nil } - -// isEmptyUnstructuredObject returns true if in is an empty unstructured object, i.e. an unstructured object that does -// not have any field except apiVersion and kind. -func isEmptyUnstructuredObject(in runtime.Object) bool { - u, ok := in.(*unstructured.Unstructured) - if !ok { - return false - } - if len(u.Object) != 2 { - return false - } - if _, ok := u.Object["kind"]; !ok { - return false - } - if _, ok := u.Object["apiVersion"]; !ok { - return false - } - return true -}