func (d *DiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
	return withRetries(defaultRetries, d.serverPreferredResources)
}
ServerPreferredResources returns the supported resources with the version preferred by the
server.
package discovery
import (
	"encoding/json"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"github.com/golang/protobuf/proto"
	"github.com/googleapis/gnostic/OpenAPIv2"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/runtime/serializer"
	"k8s.io/apimachinery/pkg/version"
	"k8s.io/client-go/kubernetes/scheme"
	restclient "k8s.io/client-go/rest"
)
const (
	defaultRetries = 2
	mimePb = "application/com.github.proto-openapi.spec.v2@v1.0+protobuf"
)
type DiscoveryInterface interface {
	RESTClient() restclient.Interface
	ServerGroupsInterface
	ServerResourcesInterface
	ServerVersionInterface
	OpenAPISchemaInterface
}
type CachedDiscoveryInterface interface {
	DiscoveryInterface
	Fresh() bool
	Invalidate()
}
type ServerGroupsInterface interface {
	ServerGroups() (*metav1.APIGroupList, error)
}
type ServerResourcesInterface interface {
	ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error)
	ServerResources() ([]*metav1.APIResourceList, error)
	ServerPreferredResources() ([]*metav1.APIResourceList, error)
	ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error)
}
type ServerVersionInterface interface {
	ServerVersion() (*version.Info, error)
}
type OpenAPISchemaInterface interface {
	OpenAPISchema() (*openapi_v2.Document, error)
}
type DiscoveryClient struct {
	restClient restclient.Interface
	LegacyPrefix string
}
func apiVersionsToAPIGroup(apiVersions *metav1.APIVersions) (apiGroup metav1.APIGroup) {
	groupVersions := []metav1.GroupVersionForDiscovery{}
	for _, version := range apiVersions.Versions {
		groupVersion := metav1.GroupVersionForDiscovery{
			GroupVersion: version,
			Version:      version,
		}
		groupVersions = append(groupVersions, groupVersion)
	}
	apiGroup.Versions = groupVersions
	apiGroup.PreferredVersion = groupVersions[0]
	return
}
func (d *DiscoveryClient) ServerGroups() (apiGroupList *metav1.APIGroupList, err error) {
	v := &metav1.APIVersions{}
	err = d.restClient.Get().AbsPath(d.LegacyPrefix).Do().Into(v)
	apiGroup := metav1.APIGroup{}
	if err == nil && len(v.Versions) != 0 {
		apiGroup = apiVersionsToAPIGroup(v)
	}
	if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
		return nil, err
	}
	apiGroupList = &metav1.APIGroupList{}
	err = d.restClient.Get().AbsPath("/apis").Do().Into(apiGroupList)
	if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
		return nil, err
	}
	if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
		apiGroupList = &metav1.APIGroupList{}
	}
	if len(v.Versions) != 0 {
		apiGroupList.Groups = append([]metav1.APIGroup{apiGroup}, apiGroupList.Groups...)
	}
	return apiGroupList, nil
}
func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *metav1.APIResourceList, err error) {
	url := url.URL{}
	if len(groupVersion) == 0 {
		return nil, fmt.Errorf("groupVersion shouldn't be empty")
	}
	if len(d.LegacyPrefix) > 0 && groupVersion == "v1" {
		url.Path = d.LegacyPrefix + "/" + groupVersion
	} else {
		url.Path = "/apis/" + groupVersion
	}
	resources = &metav1.APIResourceList{
		GroupVersion: groupVersion,
	}
	err = d.restClient.Get().AbsPath(url.String()).Do().Into(resources)
	if err != nil {
		if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
			return resources, nil
		}
		return nil, err
	}
	return resources, nil
}
func (d *DiscoveryClient) serverResources() ([]*metav1.APIResourceList, error) {
	apiGroups, err := d.ServerGroups()
	if err != nil {
		return nil, err
	}
	result := []*metav1.APIResourceList{}
	failedGroups := make(map[schema.GroupVersion]error)
	for _, apiGroup := range apiGroups.Groups {
		for _, version := range apiGroup.Versions {
			gv := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
			resources, err := d.ServerResourcesForGroupVersion(version.GroupVersion)
			if err != nil {
				failedGroups[gv] = err
				continue
			}
			result = append(result, resources)
		}
	}
	if len(failedGroups) == 0 {
		return result, nil
	}
	return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
}
func (d *DiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
	return withRetries(defaultRetries, d.serverResources)
}
type ErrGroupDiscoveryFailed struct {
	Groups map[schema.GroupVersion]error
}
func (e *ErrGroupDiscoveryFailed) Error() string {
	var groups []string
	for k, v := range e.Groups {
		groups = append(groups, fmt.Sprintf("%s: %v", k, v))
	}
	sort.Strings(groups)
	return fmt.Sprintf("unable to retrieve the complete list of server APIs: %s", strings.Join(groups, ", "))
}
func IsGroupDiscoveryFailedError(err error) bool {
	_, ok := err.(*ErrGroupDiscoveryFailed)
	return err != nil && ok
}
func (d *DiscoveryClient) serverPreferredResources() ([]*metav1.APIResourceList, error) {
	serverGroupList, err := d.ServerGroups()
	if err != nil {
		return nil, err
	}
	result := []*metav1.APIResourceList{}
	failedGroups := make(map[schema.GroupVersion]error)
	grVersions := map[schema.GroupResource]string{}                          
	grApiResources := map[schema.GroupResource]*metav1.APIResource{}         
	gvApiResourceLists := map[schema.GroupVersion]*metav1.APIResourceList{}  
	for _, apiGroup := range serverGroupList.Groups {
		for _, version := range apiGroup.Versions {
			groupVersion := schema.GroupVersion{Group: apiGroup.Name, Version: version.Version}
			apiResourceList, err := d.ServerResourcesForGroupVersion(version.GroupVersion)
			if err != nil {
				failedGroups[groupVersion] = err
				continue
			}
			emptyApiResourceList := metav1.APIResourceList{
				GroupVersion: version.GroupVersion,
			}
			gvApiResourceLists[groupVersion] = &emptyApiResourceList
			result = append(result, &emptyApiResourceList)
			for i := range apiResourceList.APIResources {
				apiResource := &apiResourceList.APIResources[i]
				if strings.Contains(apiResource.Name, "/") {
					continue
				}
				gv := schema.GroupResource{Group: apiGroup.Name, Resource: apiResource.Name}
				if _, ok := grApiResources[gv]; ok && version.Version != apiGroup.PreferredVersion.Version {
					continue
				}
				grVersions[gv] = version.Version
				grApiResources[gv] = apiResource
			}
		}
	}
	for groupResource, apiResource := range grApiResources {
		version := grVersions[groupResource]
		groupVersion := schema.GroupVersion{Group: groupResource.Group, Version: version}
		apiResourceList := gvApiResourceLists[groupVersion]
		apiResourceList.APIResources = append(apiResourceList.APIResources, *apiResource)
	}
	if len(failedGroups) == 0 {
		return result, nil
	}
	return result, &ErrGroupDiscoveryFailed{Groups: failedGroups}
}