From 9fa87b55f6c8f07ee14528ba47a82694168dc151 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Tue, 14 Nov 2017 22:16:10 -0500 Subject: [PATCH] Add a lazy discovery interface for Unstructured Delays the error until the first call and then preserves it for others. More closely matches the intent of the Object() calls. Loaders are now lazy and don't need to return errors directly. Sets the stage for collapsing unstructured and structured builders together. Kubernetes-commit: e298aa39c3de8ad1059861b7f78d62005ca87f88 --- discovery/unstructured.go | 44 +++++++++++++++++++++++++++------------ dynamic/dynamic_util.go | 2 +- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/discovery/unstructured.go b/discovery/unstructured.go index 4a0fd643..fa7f2ec0 100644 --- a/discovery/unstructured.go +++ b/discovery/unstructured.go @@ -17,22 +17,28 @@ limitations under the License. package discovery import ( - "fmt" + "reflect" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) -// UnstructuredObjectTyper provides a runtime.ObjectTyper implmentation for +// UnstructuredObjectTyper provides a runtime.ObjectTyper implementation for // runtime.Unstructured object based on discovery information. type UnstructuredObjectTyper struct { registered map[schema.GroupVersionKind]bool + typers []runtime.ObjectTyper } // NewUnstructuredObjectTyper returns a runtime.ObjectTyper for -// unstructred objects based on discovery information. -func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *UnstructuredObjectTyper { - dot := &UnstructuredObjectTyper{registered: make(map[schema.GroupVersionKind]bool)} +// unstructured objects based on discovery information. It accepts a list of fallback typers +// for handling objects that are not runtime.Unstructured. It does not delegate the Recognizes +// check, only ObjectKinds. +func NewUnstructuredObjectTyper(groupResources []*APIGroupResources, typers ...runtime.ObjectTyper) *UnstructuredObjectTyper { + dot := &UnstructuredObjectTyper{ + registered: make(map[schema.GroupVersionKind]bool), + typers: typers, + } for _, group := range groupResources { for _, discoveryVersion := range group.Group.Versions { resources, ok := group.VersionedResources[discoveryVersion.Version] @@ -55,17 +61,29 @@ func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *Unstructur // because runtime.Unstructured object should always have group,version,kind // information set. func (d *UnstructuredObjectTyper) ObjectKinds(obj runtime.Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) { - if _, ok := obj.(runtime.Unstructured); !ok { - return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj) + if _, ok := obj.(runtime.Unstructured); ok { + gvk := obj.GetObjectKind().GroupVersionKind() + if len(gvk.Kind) == 0 { + return nil, false, runtime.NewMissingKindErr("object has no kind field ") + } + if len(gvk.Version) == 0 { + return nil, false, runtime.NewMissingVersionErr("object has no apiVersion field") + } + return []schema.GroupVersionKind{gvk}, false, nil } - gvk := obj.GetObjectKind().GroupVersionKind() - if len(gvk.Kind) == 0 { - return nil, false, runtime.NewMissingKindErr("unstructured object has no kind") + var lastErr error + for _, typer := range d.typers { + gvks, unversioned, err := typer.ObjectKinds(obj) + if err != nil { + lastErr = err + continue + } + return gvks, unversioned, nil } - if len(gvk.Version) == 0 { - return nil, false, runtime.NewMissingVersionErr("unstructured object has no version") + if lastErr == nil { + lastErr = runtime.NewNotRegisteredErrForType(reflect.TypeOf(obj)) } - return []schema.GroupVersionKind{gvk}, false, nil + return nil, false, lastErr } // Recognizes returns true if the provided group,version,kind was in the diff --git a/dynamic/dynamic_util.go b/dynamic/dynamic_util.go index c834dbb0..c2cf0dae 100644 --- a/dynamic/dynamic_util.go +++ b/dynamic/dynamic_util.go @@ -84,7 +84,7 @@ func NewObjectTyper(resources []*metav1.APIResourceList) (runtime.ObjectTyper, e // information. func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) { if _, ok := obj.(*unstructured.Unstructured); !ok { - return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj) + return nil, false, fmt.Errorf("type %T is invalid for determining dynamic object types", obj) } return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil }