mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-08 04:32:37 +00:00
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.
This commit is contained in:
@@ -285,14 +285,14 @@ func (f *FakeFactory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return legacyscheme.Registry.RESTMapper(), f.tf.Typer
|
||||
}
|
||||
|
||||
func (f *FakeFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
func (f *FakeFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
groupResources := testDynamicResources()
|
||||
mapper := discovery.NewRESTMapper(groupResources, meta.InterfacesForUnstructuredConversion(legacyscheme.Registry.InterfacesFor))
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
|
||||
fakeDs := &fakeCachedDiscoveryClient{}
|
||||
expander, err := cmdutil.NewShortcutExpander(mapper, fakeDs)
|
||||
return expander, typer, err
|
||||
expander := cmdutil.NewShortcutExpander(mapper, fakeDs)
|
||||
return expander, typer
|
||||
}
|
||||
|
||||
func (f *FakeFactory) CategoryExpander() categories.CategoryExpander {
|
||||
@@ -519,7 +519,7 @@ func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, isLocal bool, output
|
||||
|
||||
func (f *FakeFactory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.Object()
|
||||
unstructuredMapper, unstructuredTyper, _ := f.UnstructuredObject()
|
||||
unstructuredMapper, unstructuredTyper := f.UnstructuredObject()
|
||||
|
||||
return resource.NewBuilder(
|
||||
&resource.Mapper{
|
||||
@@ -608,7 +608,7 @@ func (f *fakeAPIFactory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return testapi.Default.RESTMapper(), legacyscheme.Scheme
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
func (f *fakeAPIFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
groupResources := testDynamicResources()
|
||||
mapper := discovery.NewRESTMapper(
|
||||
groupResources,
|
||||
@@ -629,8 +629,8 @@ func (f *fakeAPIFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTy
|
||||
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
fakeDs := &fakeCachedDiscoveryClient{}
|
||||
expander, err := cmdutil.NewShortcutExpander(mapper, fakeDs)
|
||||
return expander, typer, err
|
||||
expander := cmdutil.NewShortcutExpander(mapper, fakeDs)
|
||||
return expander, typer
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) Decoder(bool) runtime.Decoder {
|
||||
@@ -865,7 +865,7 @@ func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, isLocal bool, out
|
||||
|
||||
func (f *fakeAPIFactory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.Object()
|
||||
unstructuredMapper, unstructuredTyper, _ := f.UnstructuredObject()
|
||||
unstructuredMapper, unstructuredTyper := f.UnstructuredObject()
|
||||
|
||||
return resource.NewBuilder(
|
||||
&resource.Mapper{
|
||||
|
@@ -9,6 +9,7 @@ go_library(
|
||||
srcs = [
|
||||
"cached_discovery.go",
|
||||
"clientcache.go",
|
||||
"discovery.go",
|
||||
"factory.go",
|
||||
"factory_builder.go",
|
||||
"factory_client_access.go",
|
||||
|
@@ -191,7 +191,7 @@ type ObjectMappingFactory interface {
|
||||
Object() (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interfaces for dealing with arbitrary
|
||||
// runtime.Unstructured. This performs API calls to discover types.
|
||||
UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error)
|
||||
UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interface for expanding categories like `all`.
|
||||
// TODO: this should probably return an error if the full expander can't be loaded.
|
||||
CategoryExpander() categories.CategoryExpander
|
||||
|
@@ -51,16 +51,12 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
|
||||
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command, isLocal bool, outputOpts *printers.OutputOptions, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
var mapper meta.RESTMapper
|
||||
var typer runtime.ObjectTyper
|
||||
var err error
|
||||
|
||||
if isLocal {
|
||||
mapper = legacyscheme.Registry.RESTMapper()
|
||||
typer = legacyscheme.Scheme
|
||||
} else {
|
||||
mapper, typer, err = f.objectMappingFactory.UnstructuredObject()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mapper, typer = f.objectMappingFactory.UnstructuredObject()
|
||||
}
|
||||
// TODO: used by the custom column implementation and the name implementation, break this dependency
|
||||
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
|
||||
@@ -137,11 +133,7 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, isLocal bool, mapper meta
|
||||
|
||||
// fall back to an unstructured object if we get something unregistered
|
||||
if runtime.IsNotRegisteredError(err) {
|
||||
_, typer, unstructuredErr := f.objectMappingFactory.UnstructuredObject()
|
||||
if unstructuredErr != nil {
|
||||
// if we can't get an unstructured typer, return the original error
|
||||
return err
|
||||
}
|
||||
_, typer := f.objectMappingFactory.UnstructuredObject()
|
||||
gvks, _, err = typer.ObjectKinds(obj)
|
||||
}
|
||||
|
||||
@@ -186,7 +178,7 @@ func (f *ring2Factory) NewBuilder() *resource.Builder {
|
||||
mapper, typer := f.objectMappingFactory.Object()
|
||||
|
||||
unstructuredClientMapperFunc := resource.ClientMapperFunc(f.objectMappingFactory.UnstructuredClientForMapping)
|
||||
unstructuredMapper, unstructuredTyper, _ := f.objectMappingFactory.UnstructuredObject()
|
||||
unstructuredMapper, unstructuredTyper := f.objectMappingFactory.Object()
|
||||
|
||||
categoryExpander := f.objectMappingFactory.CategoryExpander()
|
||||
|
||||
|
@@ -27,6 +27,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -71,34 +73,35 @@ func NewObjectMappingFactory(clientAccessFactory ClientAccessFactory) ObjectMapp
|
||||
return f
|
||||
}
|
||||
|
||||
// TODO: This method should return an error now that it can fail. Alternatively, it needs to
|
||||
// return lazy implementations of mapper and typer that don't hit the wire until they are
|
||||
// invoked.
|
||||
func (f *ring1Factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
func (f *ring1Factory) objectLoader() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
mapper := legacyscheme.Registry.RESTMapper()
|
||||
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
|
||||
if err == nil {
|
||||
mapper = meta.FirstHitRESTMapper{
|
||||
MultiRESTMapper: meta.MultiRESTMapper{
|
||||
discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, legacyscheme.Registry.InterfacesFor),
|
||||
legacyscheme.Registry.RESTMapper(), // hardcoded fall back
|
||||
},
|
||||
}
|
||||
|
||||
// wrap with shortcuts, they require a discoveryClient
|
||||
mapper, err = NewShortcutExpander(mapper, discoveryClient)
|
||||
// you only have an error on missing discoveryClient, so this shouldn't fail. Check anyway.
|
||||
CheckErr(err)
|
||||
if err != nil {
|
||||
glog.V(5).Infof("Object loader was unable to retrieve a discovery client: %v", err)
|
||||
return mapper, legacyscheme.Scheme, nil
|
||||
}
|
||||
mapper = meta.FirstHitRESTMapper{
|
||||
MultiRESTMapper: meta.MultiRESTMapper{
|
||||
discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, legacyscheme.Registry.InterfacesFor),
|
||||
legacyscheme.Registry.RESTMapper(), // hardcoded fall back
|
||||
},
|
||||
}
|
||||
|
||||
return mapper, legacyscheme.Scheme
|
||||
// wrap with shortcuts, they require a discoveryClient
|
||||
mapper = NewShortcutExpander(mapper, discoveryClient)
|
||||
return mapper, legacyscheme.Scheme, nil
|
||||
}
|
||||
|
||||
func (f *ring1Factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
// TODO: unstructured and structured discovery should both gracefully degrade in the presence
|
||||
// of errors, and it should be possible to get access to the unstructured object typers no matter
|
||||
// whether the server responds or not. Make the legacy scheme recognize object typer, then we can
|
||||
// safely fall back to the built in restmapper as a last resort.
|
||||
func (f *ring1Factory) unstructuredObjectLoader() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
discoveryClient, err := f.clientAccessFactory.DiscoveryClient()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
groupResources, err := discovery.GetAPIGroupResources(discoveryClient)
|
||||
if err != nil && !discoveryClient.Fresh() {
|
||||
discoveryClient.Invalidate()
|
||||
@@ -112,10 +115,18 @@ func (f *ring1Factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectType
|
||||
interfaces := meta.InterfacesForUnstructuredConversion(legacyscheme.Registry.InterfacesFor)
|
||||
mapper := discovery.NewDeferredDiscoveryRESTMapper(discoveryClient, meta.VersionInterfacesFunc(interfaces))
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
expander, err := NewShortcutExpander(mapper, discoveryClient)
|
||||
expander := NewShortcutExpander(mapper, discoveryClient)
|
||||
return expander, typer, err
|
||||
}
|
||||
|
||||
func (f *ring1Factory) Object() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return NewLazyObjectLoader(f.objectLoader)
|
||||
}
|
||||
|
||||
func (f *ring1Factory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return NewLazyObjectLoader(f.unstructuredObjectLoader)
|
||||
}
|
||||
|
||||
func (f *ring1Factory) CategoryExpander() categories.CategoryExpander {
|
||||
legacyExpander := categories.LegacyCategoryExpander
|
||||
|
||||
|
@@ -539,10 +539,7 @@ func TestDiscoveryReplaceAliases(t *testing.T) {
|
||||
}
|
||||
|
||||
ds := &fakeDiscoveryClient{}
|
||||
mapper, err := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create shortcut expander, err = %s", err.Error())
|
||||
}
|
||||
mapper := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
|
||||
b := resource.NewBuilder(
|
||||
&resource.Mapper{
|
||||
RESTMapper: mapper,
|
||||
|
@@ -17,7 +17,6 @@ limitations under the License.
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
@@ -37,11 +36,8 @@ type shortcutExpander struct {
|
||||
|
||||
var _ meta.RESTMapper = &shortcutExpander{}
|
||||
|
||||
func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInterface) (shortcutExpander, error) {
|
||||
if client == nil {
|
||||
return shortcutExpander{}, errors.New("Please provide discovery client to shortcut expander")
|
||||
}
|
||||
return shortcutExpander{RESTMapper: delegate, discoveryClient: client}, nil
|
||||
func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInterface) shortcutExpander {
|
||||
return shortcutExpander{RESTMapper: delegate, discoveryClient: client}
|
||||
}
|
||||
|
||||
func (e shortcutExpander) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
|
@@ -71,10 +71,7 @@ func TestReplaceAliases(t *testing.T) {
|
||||
}
|
||||
|
||||
ds := &fakeDiscoveryClient{}
|
||||
mapper, err := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create shortcut expander, err %s", err.Error())
|
||||
}
|
||||
mapper := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
|
||||
|
||||
for _, test := range tests {
|
||||
ds.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {
|
||||
@@ -126,10 +123,7 @@ func TestKindFor(t *testing.T) {
|
||||
}
|
||||
|
||||
ds := &fakeDiscoveryClient{}
|
||||
mapper, err := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create shortcut expander, err %s", err.Error())
|
||||
}
|
||||
mapper := NewShortcutExpander(testapi.Default.RESTMapper(), ds)
|
||||
|
||||
for i, test := range tests {
|
||||
ds.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {
|
||||
|
@@ -34,6 +34,7 @@ go_library(
|
||||
"firsthit_restmapper.go",
|
||||
"help.go",
|
||||
"interfaces.go",
|
||||
"lazy.go",
|
||||
"meta.go",
|
||||
"multirestmapper.go",
|
||||
"priority.go",
|
||||
|
121
staging/src/k8s.io/apimachinery/pkg/api/meta/lazy.go
Normal file
121
staging/src/k8s.io/apimachinery/pkg/api/meta/lazy.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package meta
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// lazyObject defers loading the mapper and typer until necessary.
|
||||
type lazyObject struct {
|
||||
loader func() (RESTMapper, runtime.ObjectTyper, error)
|
||||
|
||||
lock sync.Mutex
|
||||
loaded bool
|
||||
err error
|
||||
mapper RESTMapper
|
||||
typer runtime.ObjectTyper
|
||||
}
|
||||
|
||||
// NewLazyObjectLoader handles unrecoverable errors when creating a RESTMapper / ObjectTyper by
|
||||
// returning those initialization errors when the interface methods are invoked. This defers the
|
||||
// initialization and any server calls until a client actually needs to perform the action.
|
||||
func NewLazyObjectLoader(fn func() (RESTMapper, runtime.ObjectTyper, error)) (RESTMapper, runtime.ObjectTyper) {
|
||||
obj := &lazyObject{loader: fn}
|
||||
return obj, obj
|
||||
}
|
||||
|
||||
// init lazily loads the mapper and typer, returning an error if initialization has failed.
|
||||
func (o *lazyObject) init() error {
|
||||
o.lock.Lock()
|
||||
defer o.lock.Unlock()
|
||||
if o.loaded {
|
||||
return o.err
|
||||
}
|
||||
o.mapper, o.typer, o.err = o.loader()
|
||||
o.loaded = true
|
||||
return o.err
|
||||
}
|
||||
|
||||
var _ RESTMapper = &lazyObject{}
|
||||
var _ runtime.ObjectTyper = &lazyObject{}
|
||||
|
||||
func (o *lazyObject) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return schema.GroupVersionKind{}, err
|
||||
}
|
||||
return o.mapper.KindFor(resource)
|
||||
}
|
||||
|
||||
func (o *lazyObject) KindsFor(resource schema.GroupVersionResource) ([]schema.GroupVersionKind, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return []schema.GroupVersionKind{}, err
|
||||
}
|
||||
return o.mapper.KindsFor(resource)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ResourceFor(input schema.GroupVersionResource) (schema.GroupVersionResource, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return schema.GroupVersionResource{}, err
|
||||
}
|
||||
return o.mapper.ResourceFor(input)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ResourcesFor(input schema.GroupVersionResource) ([]schema.GroupVersionResource, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return []schema.GroupVersionResource{}, err
|
||||
}
|
||||
return o.mapper.ResourcesFor(input)
|
||||
}
|
||||
|
||||
func (o *lazyObject) RESTMapping(gk schema.GroupKind, versions ...string) (*RESTMapping, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.mapper.RESTMapping(gk, versions...)
|
||||
}
|
||||
|
||||
func (o *lazyObject) RESTMappings(gk schema.GroupKind, versions ...string) ([]*RESTMapping, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.mapper.RESTMappings(gk, versions...)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
if err := o.init(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return o.mapper.ResourceSingularizer(resource)
|
||||
}
|
||||
|
||||
func (o *lazyObject) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
if err := o.init(); err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return o.typer.ObjectKinds(obj)
|
||||
}
|
||||
|
||||
func (o *lazyObject) Recognizes(gvk schema.GroupVersionKind) bool {
|
||||
if err := o.init(); err != nil {
|
||||
return false
|
||||
}
|
||||
return o.typer.Recognizes(gvk)
|
||||
}
|
@@ -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
|
||||
|
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user