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 <andy.goldstein@redhat.com>
This commit is contained in:
Andy Goldstein 2022-10-18 16:34:28 -04:00
parent 0bdcb93b06
commit 0976267f0f
No known key found for this signature in database
GPG Key ID: 409C2BE062A844A4
2 changed files with 27 additions and 28 deletions

View File

@ -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
}

View File

@ -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
}