mirror of
https://github.com/kubernetes/client-go.git
synced 2025-06-25 06:31:35 +00:00
restmapper: re-try shortcut expander after not-found error
Kubernetes-commit: f7d1eb7726fa511b6439b7f8162138742ac639ab
This commit is contained in:
parent
cf13620092
commit
e2598a43a3
@ -43,7 +43,18 @@ func NewShortcutExpander(delegate meta.RESTMapper, client discovery.DiscoveryInt
|
|||||||
|
|
||||||
// KindFor fulfills meta.RESTMapper
|
// KindFor fulfills meta.RESTMapper
|
||||||
func (e shortcutExpander) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
func (e shortcutExpander) KindFor(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
|
||||||
return e.RESTMapper.KindFor(e.expandResourceShortcut(resource))
|
// expandResourceShortcut works with current API resources as read from discovery cache.
|
||||||
|
// In case of new CRDs this means we potentially don't have current state of discovery.
|
||||||
|
// In the current wiring in k8s.io/cli-runtime/pkg/genericclioptions/config_flags.go#toRESTMapper,
|
||||||
|
// we are using DeferredDiscoveryRESTMapper which on KindFor failure will clear the
|
||||||
|
// cache and fetch all data from a cluster (see vendor/k8s.io/client-go/restmapper/discovery.go#KindFor).
|
||||||
|
// Thus another call to expandResourceShortcut, after a NoMatchError should successfully
|
||||||
|
// read Kind to the user or an error.
|
||||||
|
gvk, err := e.RESTMapper.KindFor(e.expandResourceShortcut(resource))
|
||||||
|
if meta.IsNoMatchError(err) {
|
||||||
|
return e.RESTMapper.KindFor(e.expandResourceShortcut(resource))
|
||||||
|
}
|
||||||
|
return gvk, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// KindsFor fulfills meta.RESTMapper
|
// KindsFor fulfills meta.RESTMapper
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
openapi_v2 "github.com/google/gnostic/openapiv2"
|
openapi_v2 "github.com/google/gnostic/openapiv2"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
@ -195,6 +196,65 @@ func TestKindFor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestKindForWithNewCRDs(t *testing.T) {
|
||||||
|
tests := map[string]struct {
|
||||||
|
in schema.GroupVersionResource
|
||||||
|
expected schema.GroupVersionKind
|
||||||
|
srvRes []*metav1.APIResourceList
|
||||||
|
}{
|
||||||
|
"": {
|
||||||
|
in: schema.GroupVersionResource{Group: "a", Version: "", Resource: "sc"},
|
||||||
|
expected: schema.GroupVersionKind{Group: "a", Version: "v1", Kind: "StorageClass"},
|
||||||
|
srvRes: []*metav1.APIResourceList{
|
||||||
|
{
|
||||||
|
GroupVersion: "a/v1",
|
||||||
|
APIResources: []metav1.APIResource{
|
||||||
|
{
|
||||||
|
Name: "storageclasses",
|
||||||
|
ShortNames: []string{"sc"},
|
||||||
|
Kind: "StorageClass",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, test := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
invalidateCalled := false
|
||||||
|
fakeDiscovery := &fakeDiscoveryClient{}
|
||||||
|
fakeDiscovery.serverResourcesHandler = func() ([]*metav1.APIResourceList, error) {
|
||||||
|
if invalidateCalled {
|
||||||
|
return test.srvRes, nil
|
||||||
|
}
|
||||||
|
return []*metav1.APIResourceList{}, nil
|
||||||
|
}
|
||||||
|
fakeCachedDiscovery := &fakeCachedDiscoveryClient{DiscoveryInterface: fakeDiscovery}
|
||||||
|
fakeCachedDiscovery.invalidateHandler = func() {
|
||||||
|
invalidateCalled = true
|
||||||
|
}
|
||||||
|
fakeCachedDiscovery.freshHandler = func() bool {
|
||||||
|
return invalidateCalled
|
||||||
|
}
|
||||||
|
|
||||||
|
// in real world the discovery client is fronted with a cache which
|
||||||
|
// will answer the initial request, only failure to match will trigger
|
||||||
|
// the cache invalidation and live discovery call
|
||||||
|
delegate := NewDeferredDiscoveryRESTMapper(fakeCachedDiscovery)
|
||||||
|
mapper := NewShortcutExpander(delegate, fakeCachedDiscovery)
|
||||||
|
|
||||||
|
gvk, err := mapper.KindFor(test.in)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if diff := cmp.Equal(gvk, test.expected); !diff {
|
||||||
|
t.Errorf("unexpected data returned %#v, expected %#v", gvk, test.expected)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type fakeRESTMapper struct {
|
type fakeRESTMapper struct {
|
||||||
kindForInput schema.GroupVersionResource
|
kindForInput schema.GroupVersionResource
|
||||||
}
|
}
|
||||||
@ -301,3 +361,24 @@ func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
|||||||
func (c *fakeDiscoveryClient) OpenAPIV3() openapi.Client {
|
func (c *fakeDiscoveryClient) OpenAPIV3() openapi.Client {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fakeCachedDiscoveryClient struct {
|
||||||
|
discovery.DiscoveryInterface
|
||||||
|
freshHandler func() bool
|
||||||
|
invalidateHandler func()
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ discovery.CachedDiscoveryInterface = &fakeCachedDiscoveryClient{}
|
||||||
|
|
||||||
|
func (c *fakeCachedDiscoveryClient) Fresh() bool {
|
||||||
|
if c.freshHandler != nil {
|
||||||
|
return c.freshHandler()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeCachedDiscoveryClient) Invalidate() {
|
||||||
|
if c.invalidateHandler != nil {
|
||||||
|
c.invalidateHandler()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user