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
This commit is contained in:
Clayton Coleman 2017-11-14 22:16:10 -05:00 committed by Kubernetes Publisher
parent f14e54e4a9
commit 9fa87b55f6
2 changed files with 32 additions and 14 deletions

View File

@ -17,22 +17,28 @@ limitations under the License.
package discovery package discovery
import ( import (
"fmt" "reflect"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "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. // runtime.Unstructured object based on discovery information.
type UnstructuredObjectTyper struct { type UnstructuredObjectTyper struct {
registered map[schema.GroupVersionKind]bool registered map[schema.GroupVersionKind]bool
typers []runtime.ObjectTyper
} }
// NewUnstructuredObjectTyper returns a runtime.ObjectTyper for // NewUnstructuredObjectTyper returns a runtime.ObjectTyper for
// unstructred objects based on discovery information. // unstructured objects based on discovery information. It accepts a list of fallback typers
func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *UnstructuredObjectTyper { // for handling objects that are not runtime.Unstructured. It does not delegate the Recognizes
dot := &UnstructuredObjectTyper{registered: make(map[schema.GroupVersionKind]bool)} // 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 _, group := range groupResources {
for _, discoveryVersion := range group.Group.Versions { for _, discoveryVersion := range group.Group.Versions {
resources, ok := group.VersionedResources[discoveryVersion.Version] 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 // because runtime.Unstructured object should always have group,version,kind
// information set. // information set.
func (d *UnstructuredObjectTyper) ObjectKinds(obj runtime.Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) { func (d *UnstructuredObjectTyper) ObjectKinds(obj runtime.Object) (gvks []schema.GroupVersionKind, unversionedType bool, err error) {
if _, ok := obj.(runtime.Unstructured); !ok { if _, ok := obj.(runtime.Unstructured); ok {
return nil, false, fmt.Errorf("type %T is invalid for dynamic object typer", obj)
}
gvk := obj.GetObjectKind().GroupVersionKind() gvk := obj.GetObjectKind().GroupVersionKind()
if len(gvk.Kind) == 0 { if len(gvk.Kind) == 0 {
return nil, false, runtime.NewMissingKindErr("unstructured object has no kind") return nil, false, runtime.NewMissingKindErr("object has no kind field ")
} }
if len(gvk.Version) == 0 { if len(gvk.Version) == 0 {
return nil, false, runtime.NewMissingVersionErr("unstructured object has no version") return nil, false, runtime.NewMissingVersionErr("object has no apiVersion field")
} }
return []schema.GroupVersionKind{gvk}, false, nil return []schema.GroupVersionKind{gvk}, false, nil
}
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 lastErr == nil {
lastErr = runtime.NewNotRegisteredErrForType(reflect.TypeOf(obj))
}
return nil, false, lastErr
} }
// Recognizes returns true if the provided group,version,kind was in the // Recognizes returns true if the provided group,version,kind was in the

View File

@ -84,7 +84,7 @@ func NewObjectTyper(resources []*metav1.APIResourceList) (runtime.ObjectTyper, e
// information. // information.
func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) { func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
if _, ok := obj.(*unstructured.Unstructured); !ok { 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 return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
} }