Skip to content

Commit

Permalink
GVKForObject should handle multiple GVKs in Scheme gracefully
Browse files Browse the repository at this point in the history
- If the user sets the GVK, make sure that's in the list of the GVK
  returned from the Scheme.
- Always print out the multiple GVKs when erroring out
- Add more comments on where to find more information about this issue

Signed-off-by: Vince Prignano <vincepri@redhat.com>
  • Loading branch information
vincepri committed Feb 13, 2023
1 parent c98b7fd commit 67d3283
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions pkg/client/apiutil/apimachinery.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
return gvk, nil
}

// Use the given scheme to retrieve all the GVKs for the object.
gvks, isUnversioned, err := scheme.ObjectKinds(obj)
if err != nil {
return schema.GroupVersionKind{}, err
Expand All @@ -140,16 +141,39 @@ func GVKForObject(obj runtime.Object, scheme *runtime.Scheme) (schema.GroupVersi
return schema.GroupVersionKind{}, fmt.Errorf("cannot create group-version-kind for unversioned type %T", obj)
}

if len(gvks) < 1 {
return schema.GroupVersionKind{}, fmt.Errorf("no group-version-kinds associated with type %T", obj)
}
if len(gvks) > 1 {
// this should only trigger for things like metav1.XYZ --
// normal versioned types should be fine
switch {
case len(gvks) < 1:
// If the object has no GVK, the object might not have been registered with the scheme.
// or it's not a valid object.
return schema.GroupVersionKind{}, fmt.Errorf("no GroupVersionKind associated with type %T, was the type registered with the Scheme?", obj)
case len(gvks) > 1:
err := fmt.Errorf("multiple GroupVersionKinds associated with Go type %T within the Scheme, this can happen when a type is registered for multiple GVKs at the same time", obj)

// We've found multiple GVKs for the object.
currentGVK := obj.GetObjectKind().GroupVersionKind()
if !currentGVK.Empty() {
// If the base object has a GVK, check if it's in the list of GVKs before using it.
for _, gvk := range gvks {
if gvk == currentGVK {
return gvk, nil
}
}

return schema.GroupVersionKind{}, fmt.Errorf(
"%w: the object's supplied GroupVersionKind %q was not found in the Scheme's list; refusing to guess at one: %q", err, currentGVK, gvks)
}

// This should only trigger for things like metav1.XYZ --
// normal versioned types should be fine.
//
// See https://github.com/kubernetes-sigs/controller-runtime/issues/362
// for more information.
return schema.GroupVersionKind{}, fmt.Errorf(
"multiple group-version-kinds associated with type %T, refusing to guess at one", obj)
"%w: callers can either fix their type registration to only register it once, or specify the GroupVersionKind to use for object passed in; refusing to guess at one: %q", err, gvks)
default:
// In any other case, we've found a single GVK for the object.
return gvks[0], nil
}
return gvks[0], nil
}

// RESTClientForGVK constructs a new rest.Interface capable of accessing the resource associated
Expand Down

0 comments on commit 67d3283

Please sign in to comment.