diff options
Diffstat (limited to 'vendor/k8s.io/client-go/discovery')
-rw-r--r-- | vendor/k8s.io/client-go/discovery/discovery_client.go | 86 | ||||
-rw-r--r-- | vendor/k8s.io/client-go/discovery/restmapper.go | 31 | ||||
-rw-r--r-- | vendor/k8s.io/client-go/discovery/unstructured.go | 66 |
3 files changed, 80 insertions, 103 deletions
diff --git a/vendor/k8s.io/client-go/discovery/discovery_client.go b/vendor/k8s.io/client-go/discovery/discovery_client.go index 011dd9ecf..24c11f33b 100644 --- a/vendor/k8s.io/client-go/discovery/discovery_client.go +++ b/vendor/k8s.io/client-go/discovery/discovery_client.go @@ -23,10 +23,9 @@ import ( "sort" "strings" - "github.com/emicklei/go-restful-swagger12" + "github.com/golang/protobuf/proto" + "github.com/googleapis/gnostic/OpenAPIv2" - "github.com/go-openapi/loads" - "github.com/go-openapi/spec" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -34,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/client-go/pkg/api/v1" restclient "k8s.io/client-go/rest" ) @@ -48,14 +46,17 @@ type DiscoveryInterface interface { ServerGroupsInterface ServerResourcesInterface ServerVersionInterface - SwaggerSchemaInterface OpenAPISchemaInterface } // CachedDiscoveryInterface is a DiscoveryInterface with cache invalidation and freshness. type CachedDiscoveryInterface interface { DiscoveryInterface - // Fresh returns true if no cached data was used that had been retrieved before the instantiation. + // Fresh is supposed to tell the caller whether or not to retry if the cache + // fails to find something (false = retry, true = no need to retry). + // + // TODO: this needs to be revisited, this interface can't be locked properly + // and doesn't make a lot of sense. Fresh() bool // Invalidate enforces that no cached data is used in the future that is older than the current time. Invalidate() @@ -88,16 +89,10 @@ type ServerVersionInterface interface { ServerVersion() (*version.Info, error) } -// SwaggerSchemaInterface has a method to retrieve the swagger schema. -type SwaggerSchemaInterface interface { - // SwaggerSchema retrieves and parses the swagger API schema the server supports. - SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) -} - // OpenAPISchemaInterface has a method to retrieve the open API schema. type OpenAPISchemaInterface interface { // OpenAPISchema retrieves and parses the swagger API schema the server supports. - OpenAPISchema() (*spec.Swagger, error) + OpenAPISchema() (*openapi_v2.Document, error) } // DiscoveryClient implements the functions that discover server-supported API groups, @@ -150,9 +145,9 @@ func (d *DiscoveryClient) ServerGroups() (apiGroupList *metav1.APIGroupList, err apiGroupList = &metav1.APIGroupList{} } - // append the group retrieved from /api to the list if not empty + // prepend the group retrieved from /api to the list if not empty if len(v.Versions) != 0 { - apiGroupList.Groups = append(apiGroupList.Groups, apiGroup) + apiGroupList.Groups = append([]metav1.APIGroup{apiGroup}, apiGroupList.Groups...) } return apiGroupList, nil } @@ -332,54 +327,18 @@ func (d *DiscoveryClient) ServerVersion() (*version.Info, error) { return &info, nil } -// SwaggerSchema retrieves and parses the swagger API schema the server supports. -// TODO: Replace usages with Open API. Tracked in https://github.com/kubernetes/kubernetes/issues/44589 -func (d *DiscoveryClient) SwaggerSchema(version schema.GroupVersion) (*swagger.ApiDeclaration, error) { - if version.Empty() { - return nil, fmt.Errorf("groupVersion cannot be empty") - } - - groupList, err := d.ServerGroups() +// OpenAPISchema fetches the open api schema using a rest client and parses the proto. +func (d *DiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { + data, err := d.restClient.Get().AbsPath("/swagger-2.0.0.pb-v1").Do().Raw() if err != nil { return nil, err } - groupVersions := metav1.ExtractGroupVersions(groupList) - // This check also takes care the case that kubectl is newer than the running endpoint - if stringDoesntExistIn(version.String(), groupVersions) { - return nil, fmt.Errorf("API version: %v is not supported by the server. Use one of: %v", version, groupVersions) - } - var path string - if len(d.LegacyPrefix) > 0 && version == v1.SchemeGroupVersion { - path = "/swaggerapi" + d.LegacyPrefix + "/" + version.Version - } else { - path = "/swaggerapi/apis/" + version.Group + "/" + version.Version - } - - body, err := d.restClient.Get().AbsPath(path).Do().Raw() + document := &openapi_v2.Document{} + err = proto.Unmarshal(data, document) if err != nil { return nil, err } - var schema swagger.ApiDeclaration - err = json.Unmarshal(body, &schema) - if err != nil { - return nil, fmt.Errorf("got '%s': %v", string(body), err) - } - return &schema, nil -} - -// OpenAPISchema fetches the open api schema using a rest client and parses the json. -// Warning: this is very expensive (~1.2s) -func (d *DiscoveryClient) OpenAPISchema() (*spec.Swagger, error) { - data, err := d.restClient.Get().AbsPath("/swagger.json").Do().Raw() - if err != nil { - return nil, err - } - msg := json.RawMessage(data) - doc, err := loads.Analyzed(msg, "") - if err != nil { - return nil, err - } - return doc.Spec(), err + return document, nil } // withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns. @@ -420,7 +379,7 @@ func NewDiscoveryClientForConfig(c *restclient.Config) (*DiscoveryClient, error) return &DiscoveryClient{restClient: client, LegacyPrefix: "/api"}, err } -// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. If +// NewDiscoveryClientForConfigOrDie creates a new DiscoveryClient for the given config. If // there is an error, it panics. func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient { client, err := NewDiscoveryClientForConfig(c) @@ -431,20 +390,11 @@ func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient { } -// New creates a new DiscoveryClient for the given RESTClient. +// NewDiscoveryClient returns a new DiscoveryClient for the given RESTClient. func NewDiscoveryClient(c restclient.Interface) *DiscoveryClient { return &DiscoveryClient{restClient: c, LegacyPrefix: "/api"} } -func stringDoesntExistIn(str string, slice []string) bool { - for _, s := range slice { - if s == str { - return false - } - } - return true -} - // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *DiscoveryClient) RESTClient() restclient.Interface { diff --git a/vendor/k8s.io/client-go/discovery/restmapper.go b/vendor/k8s.io/client-go/discovery/restmapper.go index 756669001..6d1de8c1b 100644 --- a/vendor/k8s.io/client-go/discovery/restmapper.go +++ b/vendor/k8s.io/client-go/discovery/restmapper.go @@ -49,6 +49,7 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V for _, group := range groupResources { groupPriority = append(groupPriority, group.Group.Name) + // Make sure the preferred version comes first if len(group.Group.PreferredVersion.Version) != 0 { preferred := group.Group.PreferredVersion.Version if _, ok := group.VersionedResources[preferred]; ok { @@ -72,6 +73,21 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V continue } + // Add non-preferred versions after the preferred version, in case there are resources that only exist in those versions + if discoveryVersion.Version != group.Group.PreferredVersion.Version { + resourcePriority = append(resourcePriority, schema.GroupVersionResource{ + Group: group.Group.Name, + Version: discoveryVersion.Version, + Resource: meta.AnyResource, + }) + + kindPriority = append(kindPriority, schema.GroupVersionKind{ + Group: group.Group.Name, + Version: discoveryVersion.Version, + Kind: meta.AnyKind, + }) + } + gv := schema.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version} versionMapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{gv}, versionInterfaces) @@ -80,8 +96,19 @@ func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.V if !resource.Namespaced { scope = meta.RESTScopeRoot } - versionMapper.Add(gv.WithKind(resource.Kind), scope) - // TODO only do this if it supports listing + + // this is for legacy resources and servers which don't list singular forms. For those we must still guess. + if len(resource.SingularName) == 0 { + versionMapper.Add(gv.WithKind(resource.Kind), scope) + // TODO this is producing unsafe guesses that don't actually work, but it matches previous behavior + versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope) + continue + } + + plural := gv.WithResource(resource.Name) + singular := gv.WithResource(resource.SingularName) + versionMapper.AddSpecific(gv.WithKind(resource.Kind), plural, singular, scope) + // TODO this is producing unsafe guesses that don't actually work, but it matches previous behavior versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope) } // TODO why is this type not in discovery (at least for "v1") diff --git a/vendor/k8s.io/client-go/discovery/unstructured.go b/vendor/k8s.io/client-go/discovery/unstructured.go index ee72d668b..fa7f2ec06 100644 --- a/vendor/k8s.io/client-go/discovery/unstructured.go +++ b/vendor/k8s.io/client-go/discovery/unstructured.go @@ -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] @@ -49,29 +55,35 @@ func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *Unstructur return dot } -// ObjectKind returns the group,version,kind of the provided object, or an error -// if the object in not runtime.Unstructured or has no group,version,kind -// information. -func (d *UnstructuredObjectTyper) ObjectKind(obj runtime.Object) (schema.GroupVersionKind, error) { - if _, ok := obj.(runtime.Unstructured); !ok { - return schema.GroupVersionKind{}, fmt.Errorf("type %T is invalid for dynamic object typer", obj) - } - - return obj.GetObjectKind().GroupVersionKind(), nil -} - // ObjectKinds returns a slice of one element with the group,version,kind of the // provided object, or an error if the object is not runtime.Unstructured or // has no group,version,kind information. unversionedType will always be false // 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) { - gvk, err := d.ObjectKind(obj) - if err != nil { - return nil, false, err + 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 } - - 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 @@ -80,16 +92,4 @@ func (d *UnstructuredObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool { return d.registered[gvk] } -// IsUnversioned returns false always because runtime.Unstructured objects -// should always have group,version,kind information set. ok will be true if the -// object's group,version,kind is api.Registry. -func (d *UnstructuredObjectTyper) IsUnversioned(obj runtime.Object) (unversioned bool, ok bool) { - gvk, err := d.ObjectKind(obj) - if err != nil { - return false, false - } - - return false, d.registered[gvk] -} - var _ runtime.ObjectTyper = &UnstructuredObjectTyper{} |