mirror of https://github.com/k3s-io/k3s
Merge pull request #73345 from sttts/sttts-speedup-cache-miss-kubectl
discovery: speedup kubectl restmapper cache misses by a two-digit factorpull/564/head
commit
64ce2e598f
|
@ -948,10 +948,15 @@ func (_ *fakeServerResources) ServerResourcesForGroupVersion(groupVersion string
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (_ *fakeServerResources) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (_ *fakeServerResources) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (_ *fakeServerResources) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f *fakeServerResources) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
func (f *fakeServerResources) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
f.Lock.Lock()
|
f.Lock.Lock()
|
||||||
defer f.Lock.Unlock()
|
defer f.Lock.Unlock()
|
||||||
|
|
|
@ -275,10 +275,15 @@ func (d *fakeCachedDiscoveryClient) Fresh() bool {
|
||||||
func (d *fakeCachedDiscoveryClient) Invalidate() {
|
func (d *fakeCachedDiscoveryClient) Invalidate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (d *fakeCachedDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (d *fakeCachedDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
return []*metav1.APIResourceList{}, nil
|
return []*metav1.APIResourceList{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *fakeCachedDiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return []*metav1.APIGroup{}, []*metav1.APIResourceList{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// TestFactory extends cmdutil.Factory
|
// TestFactory extends cmdutil.Factory
|
||||||
type TestFactory struct {
|
type TestFactory struct {
|
||||||
cmdutil.Factory
|
cmdutil.Factory
|
||||||
|
|
|
@ -405,10 +405,16 @@ func (d *fakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*me
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerResources returns the supported resources for all groups and versions.
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (d *fakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (d *fakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerGroupsAndResources returns the supported groups and resources for all groups and versions.
|
||||||
|
func (d *fakeDiscovery) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||||
// server.
|
// server.
|
||||||
func (d *fakeDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
func (d *fakeDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
|
|
@ -118,10 +118,16 @@ func (d *memCacheClient) ServerResourcesForGroupVersion(groupVersion string) (*m
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerResources returns the supported resources for all groups and versions.
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (d *memCacheClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (d *memCacheClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
return discovery.ServerResources(d)
|
return discovery.ServerResources(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerGroupsAndResources returns the groups and supported resources for all groups and versions.
|
||||||
|
func (d *memCacheClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return discovery.ServerGroupsAndResources(d)
|
||||||
|
}
|
||||||
|
|
||||||
func (d *memCacheClient) ServerGroups() (*metav1.APIGroupList, error) {
|
func (d *memCacheClient) ServerGroups() (*metav1.APIGroupList, error) {
|
||||||
d.lock.Lock()
|
d.lock.Lock()
|
||||||
defer d.lock.Unlock()
|
defer d.lock.Unlock()
|
||||||
|
|
|
@ -90,8 +90,15 @@ func (d *CachedDiscoveryClient) ServerResourcesForGroupVersion(groupVersion stri
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerResources returns the supported resources for all groups and versions.
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (d *CachedDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (d *CachedDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
return ServerResources(d)
|
_, rs, err := ServerGroupsAndResources(d)
|
||||||
|
return rs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerGroupsAndResources returns the supported groups and resources for all groups and versions.
|
||||||
|
func (d *CachedDiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return ServerGroupsAndResources(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||||
|
|
|
@ -112,6 +112,10 @@ func (c *fakeDiscoveryClient) RESTClient() restclient.Interface {
|
||||||
|
|
||||||
func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
|
func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
|
||||||
c.groupCalls = c.groupCalls + 1
|
c.groupCalls = c.groupCalls + 1
|
||||||
|
return c.serverGroups()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeDiscoveryClient) serverGroups() (*metav1.APIGroupList, error) {
|
||||||
return &metav1.APIGroupList{
|
return &metav1.APIGroupList{
|
||||||
Groups: []metav1.APIGroup{
|
Groups: []metav1.APIGroup{
|
||||||
{
|
{
|
||||||
|
@ -140,12 +144,26 @@ func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string
|
||||||
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
_, rs, err := c.ServerGroupsAndResources()
|
||||||
|
return rs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeDiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
c.resourceCalls = c.resourceCalls + 1
|
c.resourceCalls = c.resourceCalls + 1
|
||||||
if c.serverResourcesHandler != nil {
|
|
||||||
return c.serverResourcesHandler()
|
gs, _ := c.serverGroups()
|
||||||
|
resultGroups := []*metav1.APIGroup{}
|
||||||
|
for i := range gs.Groups {
|
||||||
|
resultGroups = append(resultGroups, &gs.Groups[i])
|
||||||
}
|
}
|
||||||
return []*metav1.APIResourceList{}, nil
|
|
||||||
|
if c.serverResourcesHandler != nil {
|
||||||
|
rs, err := c.serverResourcesHandler()
|
||||||
|
return resultGroups, rs, err
|
||||||
|
}
|
||||||
|
return resultGroups, []*metav1.APIResourceList{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
|
|
@ -88,12 +88,28 @@ type ServerResourcesInterface interface {
|
||||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||||
ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error)
|
ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error)
|
||||||
// ServerResources returns the supported resources for all groups and versions.
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
|
//
|
||||||
|
// The returned resource list might be non-nil with partial results even in the case of
|
||||||
|
// non-nil error.
|
||||||
|
//
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
ServerResources() ([]*metav1.APIResourceList, error)
|
ServerResources() ([]*metav1.APIResourceList, error)
|
||||||
|
// ServerResources returns the supported groups and resources for all groups and versions.
|
||||||
|
//
|
||||||
|
// The returned group and resource lists might be non-nil with partial results even in the
|
||||||
|
// case of non-nil error.
|
||||||
|
ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error)
|
||||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||||
// server.
|
// server.
|
||||||
|
//
|
||||||
|
// The returned group and resource lists might be non-nil with partial results even in the
|
||||||
|
// case of non-nil error.
|
||||||
ServerPreferredResources() ([]*metav1.APIResourceList, error)
|
ServerPreferredResources() ([]*metav1.APIResourceList, error)
|
||||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||||
// version preferred by the server.
|
// version preferred by the server.
|
||||||
|
//
|
||||||
|
// The returned resource list might be non-nil with partial results even in the case of
|
||||||
|
// non-nil error.
|
||||||
ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error)
|
ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,14 +207,18 @@ func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (r
|
||||||
return resources, nil
|
return resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverResources returns the supported resources for all groups and versions.
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
func (d *DiscoveryClient) serverResources() ([]*metav1.APIResourceList, error) {
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
return ServerResources(d)
|
func (d *DiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
_, rs, err := d.ServerGroupsAndResources()
|
||||||
|
return rs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerResources returns the supported resources for all groups and versions.
|
// ServerGroupsAndResources returns the supported resources for all groups and versions.
|
||||||
func (d *DiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (d *DiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
return withRetries(defaultRetries, d.serverResources)
|
return withRetries(defaultRetries, func() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return ServerGroupsAndResources(d)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrGroupDiscoveryFailed is returned if one or more API groups fail to load.
|
// ErrGroupDiscoveryFailed is returned if one or more API groups fail to load.
|
||||||
|
@ -224,23 +244,28 @@ func IsGroupDiscoveryFailedError(err error) bool {
|
||||||
return err != nil && ok
|
return err != nil && ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverPreferredResources returns the supported resources with the version preferred by the server.
|
// ServerResources uses the provided discovery interface to look up supported resources for all groups and versions.
|
||||||
func (d *DiscoveryClient) serverPreferredResources() ([]*metav1.APIResourceList, error) {
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
return ServerPreferredResources(d)
|
func ServerResources(d DiscoveryInterface) ([]*metav1.APIResourceList, error) {
|
||||||
|
_, rs, err := ServerGroupsAndResources(d)
|
||||||
|
return rs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerResources uses the provided discovery interface to look up supported resources for all groups and versions.
|
func ServerGroupsAndResources(d DiscoveryInterface) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
func ServerResources(d DiscoveryInterface) ([]*metav1.APIResourceList, error) {
|
sgs, err := d.ServerGroups()
|
||||||
apiGroups, err := d.ServerGroups()
|
if sgs == nil {
|
||||||
if err != nil {
|
return nil, nil, err
|
||||||
return nil, err
|
}
|
||||||
|
resultGroups := []*metav1.APIGroup{}
|
||||||
|
for i := range sgs.Groups {
|
||||||
|
resultGroups = append(resultGroups, &sgs.Groups[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
groupVersionResources, failedGroups := fetchGroupVersionResources(d, apiGroups)
|
groupVersionResources, failedGroups := fetchGroupVersionResources(d, sgs)
|
||||||
|
|
||||||
// order results by group/version discovery order
|
// order results by group/version discovery order
|
||||||
result := []*metav1.APIResourceList{}
|
result := []*metav1.APIResourceList{}
|
||||||
for _, apiGroup := range apiGroups.Groups {
|
for _, apiGroup := range sgs.Groups {
|
||||||
for _, version := range apiGroup.Versions {
|
for _, version := range apiGroup.Versions {
|
||||||
gv := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
|
gv := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
|
||||||
if resources, ok := groupVersionResources[gv]; ok {
|
if resources, ok := groupVersionResources[gv]; ok {
|
||||||
|
@ -250,10 +275,10 @@ func ServerResources(d DiscoveryInterface) ([]*metav1.APIResourceList, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(failedGroups) == 0 {
|
if len(failedGroups) == 0 {
|
||||||
return result, nil
|
return resultGroups, result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
return resultGroups, result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerPreferredResources uses the provided discovery interface to look up preferred resources
|
// ServerPreferredResources uses the provided discovery interface to look up preferred resources
|
||||||
|
@ -317,7 +342,7 @@ func ServerPreferredResources(d DiscoveryInterface) ([]*metav1.APIResourceList,
|
||||||
return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetchServerResourcesForGroupVersions uses the discovery client to fetch the resources for the specified groups in parallel
|
// fetchServerResourcesForGroupVersions uses the discovery client to fetch the resources for the specified groups in parallel.
|
||||||
func fetchGroupVersionResources(d DiscoveryInterface, apiGroups *metav1.APIGroupList) (map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error) {
|
func fetchGroupVersionResources(d DiscoveryInterface, apiGroups *metav1.APIGroupList) (map[schema.GroupVersion]*metav1.APIResourceList, map[schema.GroupVersion]error) {
|
||||||
groupVersionResources := make(map[schema.GroupVersion]*metav1.APIResourceList)
|
groupVersionResources := make(map[schema.GroupVersion]*metav1.APIResourceList)
|
||||||
failedGroups := make(map[schema.GroupVersion]error)
|
failedGroups := make(map[schema.GroupVersion]error)
|
||||||
|
@ -341,7 +366,9 @@ func fetchGroupVersionResources(d DiscoveryInterface, apiGroups *metav1.APIGroup
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// TODO: maybe restrict this to NotFound errors
|
// TODO: maybe restrict this to NotFound errors
|
||||||
failedGroups[groupVersion] = err
|
failedGroups[groupVersion] = err
|
||||||
} else {
|
}
|
||||||
|
if apiResourceList != nil {
|
||||||
|
// even in case of error, some fallback might have been returned
|
||||||
groupVersionResources[groupVersion] = apiResourceList
|
groupVersionResources[groupVersion] = apiResourceList
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -355,7 +382,11 @@ func fetchGroupVersionResources(d DiscoveryInterface, apiGroups *metav1.APIGroup
|
||||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||||
// server.
|
// server.
|
||||||
func (d *DiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
func (d *DiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
return withRetries(defaultRetries, d.serverPreferredResources)
|
_, rs, err := withRetries(defaultRetries, func() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
rs, err := ServerPreferredResources(d)
|
||||||
|
return nil, rs, err
|
||||||
|
})
|
||||||
|
return rs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||||
|
@ -410,19 +441,20 @@ func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns.
|
// withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns.
|
||||||
func withRetries(maxRetries int, f func() ([]*metav1.APIResourceList, error)) ([]*metav1.APIResourceList, error) {
|
func withRetries(maxRetries int, f func() ([]*metav1.APIGroup, []*metav1.APIResourceList, error)) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
var result []*metav1.APIResourceList
|
var result []*metav1.APIResourceList
|
||||||
|
var resultGroups []*metav1.APIGroup
|
||||||
var err error
|
var err error
|
||||||
for i := 0; i < maxRetries; i++ {
|
for i := 0; i < maxRetries; i++ {
|
||||||
result, err = f()
|
resultGroups, result, err = f()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return result, nil
|
return resultGroups, result, nil
|
||||||
}
|
}
|
||||||
if _, ok := err.(*ErrGroupDiscoveryFailed); !ok {
|
if _, ok := err.(*ErrGroupDiscoveryFailed); !ok {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result, err
|
return resultGroups, result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDiscoveryDefaults(config *restclient.Config) error {
|
func setDiscoveryDefaults(config *restclient.Config) error {
|
||||||
|
|
|
@ -53,13 +53,29 @@ func (c *FakeDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*me
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerResources returns the supported resources for all groups and versions.
|
// ServerResources returns the supported resources for all groups and versions.
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (c *FakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (c *FakeDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
_, rs, err := c.ServerGroupsAndResources()
|
||||||
|
return rs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServerGroupsAndResources returns the supported groups and resources for all groups and versions.
|
||||||
|
func (c *FakeDiscovery) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
sgs, err := c.ServerGroups()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
resultGroups := []*metav1.APIGroup{}
|
||||||
|
for i := range sgs.Groups {
|
||||||
|
resultGroups = append(resultGroups, &sgs.Groups[i])
|
||||||
|
}
|
||||||
|
|
||||||
action := testing.ActionImpl{
|
action := testing.ActionImpl{
|
||||||
Verb: "get",
|
Verb: "get",
|
||||||
Resource: schema.GroupVersionResource{Resource: "resource"},
|
Resource: schema.GroupVersionResource{Resource: "resource"},
|
||||||
}
|
}
|
||||||
c.Invokes(action, nil)
|
c.Invokes(action, nil)
|
||||||
return c.Resources, nil
|
return resultGroups, c.Resources, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerPreferredResources returns the supported resources with the version
|
// ServerPreferredResources returns the supported resources with the version
|
||||||
|
|
|
@ -36,6 +36,7 @@ go_test(
|
||||||
"//staging/src/k8s.io/client-go/discovery:go_default_library",
|
"//staging/src/k8s.io/client-go/discovery:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
"//staging/src/k8s.io/client-go/rest:go_default_library",
|
||||||
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
|
"//staging/src/k8s.io/client-go/rest/fake:go_default_library",
|
||||||
|
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
|
||||||
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
"//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library",
|
||||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||||
],
|
],
|
||||||
|
|
|
@ -145,27 +145,26 @@ func NewDiscoveryRESTMapper(groupResources []*APIGroupResources) meta.RESTMapper
|
||||||
// GetAPIGroupResources uses the provided discovery client to gather
|
// GetAPIGroupResources uses the provided discovery client to gather
|
||||||
// discovery information and populate a slice of APIGroupResources.
|
// discovery information and populate a slice of APIGroupResources.
|
||||||
func GetAPIGroupResources(cl discovery.DiscoveryInterface) ([]*APIGroupResources, error) {
|
func GetAPIGroupResources(cl discovery.DiscoveryInterface) ([]*APIGroupResources, error) {
|
||||||
apiGroups, err := cl.ServerGroups()
|
gs, rs, err := cl.ServerGroupsAndResources()
|
||||||
if err != nil {
|
if rs == nil || gs == nil {
|
||||||
if apiGroups == nil || len(apiGroups.Groups) == 0 {
|
return nil, err
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// TODO track the errors and update callers to handle partial errors.
|
// TODO track the errors and update callers to handle partial errors.
|
||||||
}
|
}
|
||||||
|
rsm := map[string]*metav1.APIResourceList{}
|
||||||
|
for _, r := range rs {
|
||||||
|
rsm[r.GroupVersion] = r
|
||||||
|
}
|
||||||
|
|
||||||
var result []*APIGroupResources
|
var result []*APIGroupResources
|
||||||
for _, group := range apiGroups.Groups {
|
for _, group := range gs {
|
||||||
groupResources := &APIGroupResources{
|
groupResources := &APIGroupResources{
|
||||||
Group: group,
|
Group: *group,
|
||||||
VersionedResources: make(map[string][]metav1.APIResource),
|
VersionedResources: make(map[string][]metav1.APIResource),
|
||||||
}
|
}
|
||||||
for _, version := range group.Versions {
|
for _, version := range group.Versions {
|
||||||
resources, err := cl.ServerResourcesForGroupVersion(version.GroupVersion)
|
resources, ok := rsm[version.GroupVersion]
|
||||||
if err != nil {
|
if !ok {
|
||||||
// continue as best we can
|
continue
|
||||||
// TODO track the errors and update callers to handle partial errors.
|
|
||||||
if resources == nil || len(resources.APIResources) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
groupResources.VersionedResources[version.Version] = resources.APIResources
|
groupResources.VersionedResources[version.Version] = resources.APIResources
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,11 @@ limitations under the License.
|
||||||
package restmapper
|
package restmapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
|
@ -283,10 +285,146 @@ func TestDeferredDiscoveryRESTMapper_CacheMiss(t *testing.T) {
|
||||||
assert.Equal(cdc.invalidateCalls, 2, "should HAVE called Invalidate() again after another cache-miss, but with fresh==false")
|
assert.Equal(cdc.invalidateCalls, 2, "should HAVE called Invalidate() again after another cache-miss, but with fresh==false")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAPIGroupResources(t *testing.T) {
|
||||||
|
type Test struct {
|
||||||
|
name string
|
||||||
|
|
||||||
|
discovery DiscoveryInterface
|
||||||
|
|
||||||
|
expected []*APIGroupResources
|
||||||
|
expectedError error
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range []Test{
|
||||||
|
{"nil", &fakeFailingDiscovery{nil, nil, nil, nil}, nil, nil},
|
||||||
|
{"normal",
|
||||||
|
&fakeFailingDiscovery{
|
||||||
|
[]metav1.APIGroup{aGroup, bGroup}, nil,
|
||||||
|
map[string]*metav1.APIResourceList{"a/v1": &aResources, "b/v1": &bResources}, nil,
|
||||||
|
},
|
||||||
|
[]*APIGroupResources{
|
||||||
|
{aGroup, map[string][]metav1.APIResource{"v1": {aFoo}}},
|
||||||
|
{bGroup, map[string][]metav1.APIResource{"v1": {bBar}}},
|
||||||
|
}, nil,
|
||||||
|
},
|
||||||
|
{"groups failed, but has fallback with a only",
|
||||||
|
&fakeFailingDiscovery{
|
||||||
|
[]metav1.APIGroup{aGroup}, fmt.Errorf("error fetching groups"),
|
||||||
|
map[string]*metav1.APIResourceList{"a/v1": &aResources, "b/v1": &bResources}, nil,
|
||||||
|
},
|
||||||
|
[]*APIGroupResources{
|
||||||
|
{aGroup, map[string][]metav1.APIResource{"v1": {aFoo}}},
|
||||||
|
}, nil,
|
||||||
|
},
|
||||||
|
{"groups failed, but has no fallback",
|
||||||
|
&fakeFailingDiscovery{
|
||||||
|
nil, fmt.Errorf("error fetching groups"),
|
||||||
|
map[string]*metav1.APIResourceList{"a/v1": &aResources, "b/v1": &bResources}, nil,
|
||||||
|
},
|
||||||
|
nil, fmt.Errorf("error fetching groups"),
|
||||||
|
},
|
||||||
|
{"a failed, but has fallback",
|
||||||
|
&fakeFailingDiscovery{
|
||||||
|
[]metav1.APIGroup{aGroup, bGroup}, nil,
|
||||||
|
map[string]*metav1.APIResourceList{"a/v1": &aResources, "b/v1": &bResources}, map[string]error{"a/v1": fmt.Errorf("a failed")},
|
||||||
|
},
|
||||||
|
[]*APIGroupResources{
|
||||||
|
{aGroup, map[string][]metav1.APIResource{"v1": {aFoo}}},
|
||||||
|
{bGroup, map[string][]metav1.APIResource{"v1": {bBar}}},
|
||||||
|
}, nil, // TODO: do we want this?
|
||||||
|
},
|
||||||
|
{"a failed, but has no fallback",
|
||||||
|
&fakeFailingDiscovery{
|
||||||
|
[]metav1.APIGroup{aGroup, bGroup}, nil,
|
||||||
|
map[string]*metav1.APIResourceList{"b/v1": &bResources}, map[string]error{"a/v1": fmt.Errorf("a failed")},
|
||||||
|
},
|
||||||
|
[]*APIGroupResources{
|
||||||
|
{aGroup, map[string][]metav1.APIResource{}},
|
||||||
|
{bGroup, map[string][]metav1.APIResource{"v1": {bBar}}},
|
||||||
|
}, nil, // TODO: do we want this?
|
||||||
|
},
|
||||||
|
{"a and b failed, but have fallbacks",
|
||||||
|
&fakeFailingDiscovery{
|
||||||
|
[]metav1.APIGroup{aGroup, bGroup}, nil,
|
||||||
|
map[string]*metav1.APIResourceList{"a/v1": &aResources, "b/v1": &bResources}, // TODO: both fallbacks are ignored
|
||||||
|
map[string]error{"a/v1": fmt.Errorf("a failed"), "b/v1": fmt.Errorf("b failed")},
|
||||||
|
},
|
||||||
|
[]*APIGroupResources{
|
||||||
|
{aGroup, map[string][]metav1.APIResource{"v1": {aFoo}}},
|
||||||
|
{bGroup, map[string][]metav1.APIResource{"v1": {bBar}}},
|
||||||
|
}, nil, // TODO: do we want this?
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
got, err := GetAPIGroupResources(test.discovery)
|
||||||
|
if err == nil && test.expectedError != nil {
|
||||||
|
t.Fatalf("expected error %q, but got none", test.expectedError)
|
||||||
|
} else if err != nil && test.expectedError == nil {
|
||||||
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(test.expected, got) {
|
||||||
|
t.Errorf("unexpected result:\nexpected = %s\ngot = %s", spew.Sdump(test.expected), spew.Sdump(got))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ DiscoveryInterface = &fakeFailingDiscovery{}
|
||||||
|
|
||||||
|
type fakeFailingDiscovery struct {
|
||||||
|
groups []metav1.APIGroup
|
||||||
|
groupsErr error
|
||||||
|
|
||||||
|
resourcesForGroupVersion map[string]*metav1.APIResourceList
|
||||||
|
resourcesForGroupVersionErr map[string]error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeFailingDiscovery) RESTClient() restclient.Interface {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fakeFailingDiscovery) ServerGroups() (*metav1.APIGroupList, error) {
|
||||||
|
if d.groups == nil && d.groupsErr != nil {
|
||||||
|
return nil, d.groupsErr
|
||||||
|
}
|
||||||
|
return &metav1.APIGroupList{Groups: d.groups}, d.groupsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fakeFailingDiscovery) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return ServerGroupsAndResources(d)
|
||||||
|
}
|
||||||
|
func (d *fakeFailingDiscovery) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
|
||||||
|
if rs, found := d.resourcesForGroupVersion[groupVersion]; found {
|
||||||
|
return rs, d.resourcesForGroupVersionErr[groupVersion]
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fakeFailingDiscovery) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
return ServerResources(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fakeFailingDiscovery) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
return ServerPreferredResources(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *fakeFailingDiscovery) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
return ServerPreferredNamespacedResources(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeFailingDiscovery) ServerVersion() (*version.Info, error) {
|
||||||
|
return &version.Info{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeFailingDiscovery) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||||
|
panic("implement me")
|
||||||
|
}
|
||||||
|
|
||||||
type fakeCachedDiscoveryInterface struct {
|
type fakeCachedDiscoveryInterface struct {
|
||||||
invalidateCalls int
|
invalidateCalls int
|
||||||
fresh bool
|
fresh bool
|
||||||
enabledA bool
|
enabledGroupA bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ CachedDiscoveryInterface = &fakeCachedDiscoveryInterface{}
|
var _ CachedDiscoveryInterface = &fakeCachedDiscoveryInterface{}
|
||||||
|
@ -298,7 +436,7 @@ func (c *fakeCachedDiscoveryInterface) Fresh() bool {
|
||||||
func (c *fakeCachedDiscoveryInterface) Invalidate() {
|
func (c *fakeCachedDiscoveryInterface) Invalidate() {
|
||||||
c.invalidateCalls = c.invalidateCalls + 1
|
c.invalidateCalls = c.invalidateCalls + 1
|
||||||
c.fresh = true
|
c.fresh = true
|
||||||
c.enabledA = true
|
c.enabledGroupA = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeCachedDiscoveryInterface) RESTClient() restclient.Interface {
|
func (c *fakeCachedDiscoveryInterface) RESTClient() restclient.Interface {
|
||||||
|
@ -306,55 +444,33 @@ func (c *fakeCachedDiscoveryInterface) RESTClient() restclient.Interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeCachedDiscoveryInterface) ServerGroups() (*metav1.APIGroupList, error) {
|
func (c *fakeCachedDiscoveryInterface) ServerGroups() (*metav1.APIGroupList, error) {
|
||||||
if c.enabledA {
|
if c.enabledGroupA {
|
||||||
return &metav1.APIGroupList{
|
return &metav1.APIGroupList{
|
||||||
Groups: []metav1.APIGroup{
|
Groups: []metav1.APIGroup{aGroup},
|
||||||
{
|
|
||||||
Name: "a",
|
|
||||||
Versions: []metav1.GroupVersionForDiscovery{
|
|
||||||
{
|
|
||||||
GroupVersion: "a/v1",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PreferredVersion: metav1.GroupVersionForDiscovery{
|
|
||||||
GroupVersion: "a/v1",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return &metav1.APIGroupList{}, nil
|
return &metav1.APIGroupList{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *fakeCachedDiscoveryInterface) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
return ServerGroupsAndResources(c)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *fakeCachedDiscoveryInterface) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
|
func (c *fakeCachedDiscoveryInterface) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
|
||||||
if c.enabledA && groupVersion == "a/v1" {
|
if c.enabledGroupA && groupVersion == "a/v1" {
|
||||||
return &metav1.APIResourceList{
|
return &aResources, nil
|
||||||
GroupVersion: "a/v1",
|
|
||||||
APIResources: []metav1.APIResource{
|
|
||||||
{
|
|
||||||
Name: "foo",
|
|
||||||
Kind: "Foo",
|
|
||||||
Namespaced: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (c *fakeCachedDiscoveryInterface) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (c *fakeCachedDiscoveryInterface) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
if c.enabledA {
|
return ServerResources(c)
|
||||||
av1, _ := c.ServerResourcesForGroupVersion("a/v1")
|
|
||||||
return []*metav1.APIResourceList{av1}, nil
|
|
||||||
}
|
|
||||||
return []*metav1.APIResourceList{}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeCachedDiscoveryInterface) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
func (c *fakeCachedDiscoveryInterface) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
if c.enabledA {
|
if c.enabledGroupA {
|
||||||
return []*metav1.APIResourceList{
|
return []*metav1.APIResourceList{
|
||||||
{
|
{
|
||||||
GroupVersion: "a/v1",
|
GroupVersion: "a/v1",
|
||||||
|
@ -382,3 +498,50 @@ func (c *fakeCachedDiscoveryInterface) ServerVersion() (*version.Info, error) {
|
||||||
func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*openapi_v2.Document, error) {
|
func (c *fakeCachedDiscoveryInterface) OpenAPISchema() (*openapi_v2.Document, error) {
|
||||||
return &openapi_v2.Document{}, nil
|
return &openapi_v2.Document{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
aGroup = metav1.APIGroup{
|
||||||
|
Name: "a",
|
||||||
|
Versions: []metav1.GroupVersionForDiscovery{
|
||||||
|
{
|
||||||
|
GroupVersion: "a/v1",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: "a/v1",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
bGroup = metav1.APIGroup{
|
||||||
|
Name: "b",
|
||||||
|
Versions: []metav1.GroupVersionForDiscovery{
|
||||||
|
{
|
||||||
|
GroupVersion: "b/v1",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
||||||
|
GroupVersion: "b/v1",
|
||||||
|
Version: "v1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
aResources = metav1.APIResourceList{
|
||||||
|
GroupVersion: "a/v1",
|
||||||
|
APIResources: []metav1.APIResource{aFoo},
|
||||||
|
}
|
||||||
|
aFoo = metav1.APIResource{
|
||||||
|
Name: "foo",
|
||||||
|
Kind: "Foo",
|
||||||
|
Namespaced: false,
|
||||||
|
}
|
||||||
|
bResources = metav1.APIResourceList{
|
||||||
|
GroupVersion: "b/v1",
|
||||||
|
APIResources: []metav1.APIResource{bBar},
|
||||||
|
}
|
||||||
|
bBar = metav1.APIResource{
|
||||||
|
Name: "bar",
|
||||||
|
Kind: "Bar",
|
||||||
|
Namespaced: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
|
@ -265,11 +265,26 @@ func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string
|
||||||
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
return nil, errors.NewNotFound(schema.GroupResource{}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use ServerGroupsAndResources instead.
|
||||||
func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
|
||||||
if c.serverResourcesHandler != nil {
|
_, rs, err := c.ServerGroupsAndResources()
|
||||||
return c.serverResourcesHandler()
|
return rs, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *fakeDiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
||||||
|
sgs, err := c.ServerGroups()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
return []*metav1.APIResourceList{}, nil
|
resultGroups := []*metav1.APIGroup{}
|
||||||
|
for i := range sgs.Groups {
|
||||||
|
resultGroups = append(resultGroups, &sgs.Groups[i])
|
||||||
|
}
|
||||||
|
if c.serverResourcesHandler != nil {
|
||||||
|
rs, err := c.serverResourcesHandler()
|
||||||
|
return resultGroups, rs, err
|
||||||
|
}
|
||||||
|
return resultGroups, []*metav1.APIResourceList{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
||||||
|
|
Loading…
Reference in New Issue