Upgrade k8s.io/client-go to version 2
This commit is contained in:
parent
a3b95f798b
commit
6f4c5dd4ce
675 changed files with 109006 additions and 90744 deletions
385
vendor/k8s.io/client-go/discovery/discovery_client.go
generated
vendored
Normal file
385
vendor/k8s.io/client-go/discovery/discovery_client.go
generated
vendored
Normal file
|
@ -0,0 +1,385 @@
|
|||
/*
|
||||
Copyright 2015 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 discovery
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/emicklei/go-restful/swagger"
|
||||
|
||||
"k8s.io/client-go/pkg/api"
|
||||
"k8s.io/client-go/pkg/api/errors"
|
||||
"k8s.io/client-go/pkg/api/unversioned"
|
||||
"k8s.io/client-go/pkg/api/v1"
|
||||
"k8s.io/client-go/pkg/runtime"
|
||||
"k8s.io/client-go/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/pkg/version"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// DiscoveryInterface holds the methods that discover server-supported API groups,
|
||||
// versions and resources.
|
||||
type DiscoveryInterface interface {
|
||||
RESTClient() rest.Interface
|
||||
ServerGroupsInterface
|
||||
ServerResourcesInterface
|
||||
ServerVersionInterface
|
||||
SwaggerSchemaInterface
|
||||
}
|
||||
|
||||
// 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() bool
|
||||
// Invalidate enforces that no cached data is used in the future that is older than the current time.
|
||||
Invalidate()
|
||||
}
|
||||
|
||||
// ServerGroupsInterface has methods for obtaining supported groups on the API server
|
||||
type ServerGroupsInterface interface {
|
||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||
// preferred version.
|
||||
ServerGroups() (*unversioned.APIGroupList, error)
|
||||
}
|
||||
|
||||
// ServerResourcesInterface has methods for obtaining supported resources on the API server
|
||||
type ServerResourcesInterface interface {
|
||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||
ServerResourcesForGroupVersion(groupVersion string) (*unversioned.APIResourceList, error)
|
||||
// ServerResources returns the supported resources for all groups and versions.
|
||||
ServerResources() (map[string]*unversioned.APIResourceList, error)
|
||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||
// server.
|
||||
ServerPreferredResources() ([]unversioned.GroupVersionResource, error)
|
||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||
// version preferred by the server.
|
||||
ServerPreferredNamespacedResources() ([]unversioned.GroupVersionResource, error)
|
||||
}
|
||||
|
||||
// ServerVersionInterface has a method for retrieving the server's version.
|
||||
type ServerVersionInterface interface {
|
||||
// ServerVersion retrieves and parses the server's version (git version).
|
||||
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 unversioned.GroupVersion) (*swagger.ApiDeclaration, error)
|
||||
}
|
||||
|
||||
// DiscoveryClient implements the functions that discover server-supported API groups,
|
||||
// versions and resources.
|
||||
type DiscoveryClient struct {
|
||||
restClient rest.Interface
|
||||
|
||||
LegacyPrefix string
|
||||
}
|
||||
|
||||
// Convert unversioned.APIVersions to unversioned.APIGroup. APIVersions is used by legacy v1, so
|
||||
// group would be "".
|
||||
func apiVersionsToAPIGroup(apiVersions *unversioned.APIVersions) (apiGroup unversioned.APIGroup) {
|
||||
groupVersions := []unversioned.GroupVersionForDiscovery{}
|
||||
for _, version := range apiVersions.Versions {
|
||||
groupVersion := unversioned.GroupVersionForDiscovery{
|
||||
GroupVersion: version,
|
||||
Version: version,
|
||||
}
|
||||
groupVersions = append(groupVersions, groupVersion)
|
||||
}
|
||||
apiGroup.Versions = groupVersions
|
||||
// There should be only one groupVersion returned at /api
|
||||
apiGroup.PreferredVersion = groupVersions[0]
|
||||
return
|
||||
}
|
||||
|
||||
// ServerGroups returns the supported groups, with information like supported versions and the
|
||||
// preferred version.
|
||||
func (d *DiscoveryClient) ServerGroups() (apiGroupList *unversioned.APIGroupList, err error) {
|
||||
// Get the groupVersions exposed at /api
|
||||
v := &unversioned.APIVersions{}
|
||||
err = d.restClient.Get().AbsPath(d.LegacyPrefix).Do().Into(v)
|
||||
apiGroup := unversioned.APIGroup{}
|
||||
if err == nil {
|
||||
apiGroup = apiVersionsToAPIGroup(v)
|
||||
}
|
||||
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the groupVersions exposed at /apis
|
||||
apiGroupList = &unversioned.APIGroupList{}
|
||||
err = d.restClient.Get().AbsPath("/apis").Do().Into(apiGroupList)
|
||||
if err != nil && !errors.IsNotFound(err) && !errors.IsForbidden(err) {
|
||||
return nil, err
|
||||
}
|
||||
// to be compatible with a v1.0 server, if it's a 403 or 404, ignore and return whatever we got from /api
|
||||
if err != nil && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
apiGroupList = &unversioned.APIGroupList{}
|
||||
}
|
||||
|
||||
// append the group retrieved from /api to the list
|
||||
apiGroupList.Groups = append(apiGroupList.Groups, apiGroup)
|
||||
return apiGroupList, nil
|
||||
}
|
||||
|
||||
// ServerResourcesForGroupVersion returns the supported resources for a group and version.
|
||||
func (d *DiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (resources *unversioned.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 = &unversioned.APIResourceList{}
|
||||
err = d.restClient.Get().AbsPath(url.String()).Do().Into(resources)
|
||||
if err != nil {
|
||||
// ignore 403 or 404 error to be compatible with an v1.0 server.
|
||||
if groupVersion == "v1" && (errors.IsNotFound(err) || errors.IsForbidden(err)) {
|
||||
return resources, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// ServerResources returns the supported resources for all groups and versions.
|
||||
func (d *DiscoveryClient) ServerResources() (map[string]*unversioned.APIResourceList, error) {
|
||||
apiGroups, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupVersions := unversioned.ExtractGroupVersions(apiGroups)
|
||||
result := map[string]*unversioned.APIResourceList{}
|
||||
for _, groupVersion := range groupVersions {
|
||||
resources, err := d.ServerResourcesForGroupVersion(groupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result[groupVersion] = resources
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ErrGroupDiscoveryFailed is returned if one or more API groups fail to load.
|
||||
type ErrGroupDiscoveryFailed struct {
|
||||
// Groups is a list of the groups that failed to load and the error cause
|
||||
Groups map[unversioned.GroupVersion]error
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
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, ", "))
|
||||
}
|
||||
|
||||
// IsGroupDiscoveryFailedError returns true if the provided error indicates the server was unable to discover
|
||||
// a complete list of APIs for the client to use.
|
||||
func IsGroupDiscoveryFailedError(err error) bool {
|
||||
_, ok := err.(*ErrGroupDiscoveryFailed)
|
||||
return err != nil && ok
|
||||
}
|
||||
|
||||
// serverPreferredResources returns the supported resources with the version preferred by the
|
||||
// server. If namespaced is true, only namespaced resources will be returned.
|
||||
func (d *DiscoveryClient) serverPreferredResources(namespaced bool) ([]unversioned.GroupVersionResource, error) {
|
||||
// retry in case the groups supported by the server change after ServerGroup() returns.
|
||||
const maxRetries = 2
|
||||
var failedGroups map[unversioned.GroupVersion]error
|
||||
var results []unversioned.GroupVersionResource
|
||||
var resources map[unversioned.GroupResource]string
|
||||
RetrieveGroups:
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
results = []unversioned.GroupVersionResource{}
|
||||
resources = map[unversioned.GroupResource]string{}
|
||||
failedGroups = make(map[unversioned.GroupVersion]error)
|
||||
serverGroupList, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return results, err
|
||||
}
|
||||
|
||||
for _, apiGroup := range serverGroupList.Groups {
|
||||
versions := apiGroup.Versions
|
||||
for _, version := range versions {
|
||||
groupVersion := unversioned.GroupVersion{Group: apiGroup.Name, Version: version.Version}
|
||||
apiResourceList, err := d.ServerResourcesForGroupVersion(version.GroupVersion)
|
||||
if err != nil {
|
||||
if i < maxRetries-1 {
|
||||
continue RetrieveGroups
|
||||
}
|
||||
failedGroups[groupVersion] = err
|
||||
continue
|
||||
}
|
||||
for _, apiResource := range apiResourceList.APIResources {
|
||||
// ignore the root scoped resources if "namespaced" is true.
|
||||
if namespaced && !apiResource.Namespaced {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(apiResource.Name, "/") {
|
||||
continue
|
||||
}
|
||||
gvr := groupVersion.WithResource(apiResource.Name)
|
||||
if _, ok := resources[gvr.GroupResource()]; ok {
|
||||
if gvr.Version != apiGroup.PreferredVersion.Version {
|
||||
continue
|
||||
}
|
||||
// remove previous entry, because it will be replaced with a preferred one
|
||||
for i := range results {
|
||||
if results[i].GroupResource() == gvr.GroupResource() {
|
||||
results = append(results[:i], results[i+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
resources[gvr.GroupResource()] = gvr.Version
|
||||
results = append(results, gvr)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(failedGroups) == 0 {
|
||||
return results, nil
|
||||
}
|
||||
}
|
||||
return results, &ErrGroupDiscoveryFailed{Groups: failedGroups}
|
||||
}
|
||||
|
||||
// ServerPreferredResources returns the supported resources with the version preferred by the
|
||||
// server.
|
||||
func (d *DiscoveryClient) ServerPreferredResources() ([]unversioned.GroupVersionResource, error) {
|
||||
return d.serverPreferredResources(false)
|
||||
}
|
||||
|
||||
// ServerPreferredNamespacedResources returns the supported namespaced resources with the
|
||||
// version preferred by the server.
|
||||
func (d *DiscoveryClient) ServerPreferredNamespacedResources() ([]unversioned.GroupVersionResource, error) {
|
||||
return d.serverPreferredResources(true)
|
||||
}
|
||||
|
||||
// ServerVersion retrieves and parses the server's version (git version).
|
||||
func (d *DiscoveryClient) ServerVersion() (*version.Info, error) {
|
||||
body, err := d.restClient.Get().AbsPath("/version").Do().Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var info version.Info
|
||||
err = json.Unmarshal(body, &info)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("got '%s': %v", string(body), err)
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
// SwaggerSchema retrieves and parses the swagger API schema the server supports.
|
||||
func (d *DiscoveryClient) SwaggerSchema(version unversioned.GroupVersion) (*swagger.ApiDeclaration, error) {
|
||||
if version.Empty() {
|
||||
return nil, fmt.Errorf("groupVersion cannot be empty")
|
||||
}
|
||||
|
||||
groupList, err := d.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
groupVersions := unversioned.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()
|
||||
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
|
||||
}
|
||||
|
||||
func setDiscoveryDefaults(config *rest.Config) error {
|
||||
config.APIPath = ""
|
||||
config.GroupVersion = nil
|
||||
codec := runtime.NoopEncoder{Decoder: api.Codecs.UniversalDecoder()}
|
||||
config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
|
||||
if len(config.UserAgent) == 0 {
|
||||
config.UserAgent = rest.DefaultKubernetesUserAgent()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. This client
|
||||
// can be used to discover supported resources in the API server.
|
||||
func NewDiscoveryClientForConfig(c *rest.Config) (*DiscoveryClient, error) {
|
||||
config := *c
|
||||
if err := setDiscoveryDefaults(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client, err := rest.UnversionedRESTClientFor(&config)
|
||||
return &DiscoveryClient{restClient: client, LegacyPrefix: "/api"}, err
|
||||
}
|
||||
|
||||
// NewDiscoveryClientForConfig creates a new DiscoveryClient for the given config. If
|
||||
// there is an error, it panics.
|
||||
func NewDiscoveryClientForConfigOrDie(c *rest.Config) *DiscoveryClient {
|
||||
client, err := NewDiscoveryClientForConfig(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return client
|
||||
|
||||
}
|
||||
|
||||
// New creates a new DiscoveryClient for the given RESTClient.
|
||||
func NewDiscoveryClient(c rest.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() rest.Interface {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return c.restClient
|
||||
}
|
109
vendor/k8s.io/client-go/discovery/helper.go
generated
vendored
Normal file
109
vendor/k8s.io/client-go/discovery/helper.go
generated
vendored
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
Copyright 2016 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 discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/client-go/pkg/api/unversioned"
|
||||
"k8s.io/client-go/pkg/util/sets"
|
||||
"k8s.io/client-go/pkg/version"
|
||||
// Import solely to initialize client auth plugins.
|
||||
_ "k8s.io/client-go/plugin/pkg/client/auth"
|
||||
)
|
||||
|
||||
// MatchesServerVersion queries the server to compares the build version
|
||||
// (git hash) of the client with the server's build version. It returns an error
|
||||
// if it failed to contact the server or if the versions are not an exact match.
|
||||
func MatchesServerVersion(client DiscoveryInterface) error {
|
||||
cVer := version.Get()
|
||||
sVer, err := client.ServerVersion()
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't read version from server: %v\n", err)
|
||||
}
|
||||
// GitVersion includes GitCommit and GitTreeState, but best to be safe?
|
||||
if cVer.GitVersion != sVer.GitVersion || cVer.GitCommit != sVer.GitCommit || cVer.GitTreeState != sVer.GitTreeState {
|
||||
return fmt.Errorf("server version (%#v) differs from client version (%#v)!\n", sVer, cVer)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NegotiateVersion queries the server's supported api versions to find
|
||||
// a version that both client and server support.
|
||||
// - If no version is provided, try registered client versions in order of
|
||||
// preference.
|
||||
// - If version is provided and the server does not support it,
|
||||
// return an error.
|
||||
func NegotiateVersion(client DiscoveryInterface, requiredGV *unversioned.GroupVersion, clientRegisteredGVs []unversioned.GroupVersion) (*unversioned.GroupVersion, error) {
|
||||
clientVersions := sets.String{}
|
||||
for _, gv := range clientRegisteredGVs {
|
||||
clientVersions.Insert(gv.String())
|
||||
}
|
||||
groups, err := client.ServerGroups()
|
||||
if err != nil {
|
||||
// This is almost always a connection error, and higher level code should treat this as a generic error,
|
||||
// not a negotiation specific error.
|
||||
return nil, err
|
||||
}
|
||||
versions := unversioned.ExtractGroupVersions(groups)
|
||||
serverVersions := sets.String{}
|
||||
for _, v := range versions {
|
||||
serverVersions.Insert(v)
|
||||
}
|
||||
|
||||
// If version explicitly requested verify that both client and server support it.
|
||||
// If server does not support warn, but try to negotiate a lower version.
|
||||
if requiredGV != nil {
|
||||
if !clientVersions.Has(requiredGV.String()) {
|
||||
return nil, fmt.Errorf("client does not support API version %q; client supported API versions: %v", requiredGV, clientVersions)
|
||||
|
||||
}
|
||||
// If the server supports no versions, then we should just use the preferredGV
|
||||
// This can happen because discovery fails due to 403 Forbidden errors
|
||||
if len(serverVersions) == 0 {
|
||||
return requiredGV, nil
|
||||
}
|
||||
if serverVersions.Has(requiredGV.String()) {
|
||||
return requiredGV, nil
|
||||
}
|
||||
// If we are using an explicit config version the server does not support, fail.
|
||||
return nil, fmt.Errorf("server does not support API version %q", requiredGV)
|
||||
}
|
||||
|
||||
for _, clientGV := range clientRegisteredGVs {
|
||||
if serverVersions.Has(clientGV.String()) {
|
||||
// Version was not explicitly requested in command config (--api-version).
|
||||
// Ok to fall back to a supported version with a warning.
|
||||
// TODO: caesarxuchao: enable the warning message when we have
|
||||
// proper fix. Please refer to issue #14895.
|
||||
// if len(version) != 0 {
|
||||
// glog.Warningf("Server does not support API version '%s'. Falling back to '%s'.", version, clientVersion)
|
||||
// }
|
||||
t := clientGV
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
|
||||
// if we have no server versions and we have no required version, choose the first clientRegisteredVersion
|
||||
if len(serverVersions) == 0 && len(clientRegisteredGVs) > 0 {
|
||||
return &clientRegisteredGVs[0], nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to negotiate an api version; server supports: %v, client supports: %v",
|
||||
serverVersions, clientVersions)
|
||||
}
|
318
vendor/k8s.io/client-go/discovery/restmapper.go
generated
vendored
Normal file
318
vendor/k8s.io/client-go/discovery/restmapper.go
generated
vendored
Normal file
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
Copyright 2016 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 discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"k8s.io/client-go/pkg/api/errors"
|
||||
"k8s.io/client-go/pkg/api/meta"
|
||||
"k8s.io/client-go/pkg/api/unversioned"
|
||||
|
||||
"github.com/golang/glog"
|
||||
)
|
||||
|
||||
// APIGroupResources is an API group with a mapping of versions to
|
||||
// resources.
|
||||
type APIGroupResources struct {
|
||||
Group unversioned.APIGroup
|
||||
// A mapping of version string to a slice of APIResources for
|
||||
// that version.
|
||||
VersionedResources map[string][]unversioned.APIResource
|
||||
}
|
||||
|
||||
// NewRESTMapper returns a PriorityRESTMapper based on the discovered
|
||||
// groups and resources passed in.
|
||||
func NewRESTMapper(groupResources []*APIGroupResources, versionInterfaces meta.VersionInterfacesFunc) meta.RESTMapper {
|
||||
unionMapper := meta.MultiRESTMapper{}
|
||||
|
||||
var groupPriority []string
|
||||
var resourcePriority []unversioned.GroupVersionResource
|
||||
var kindPriority []unversioned.GroupVersionKind
|
||||
|
||||
for _, group := range groupResources {
|
||||
groupPriority = append(groupPriority, group.Group.Name)
|
||||
|
||||
if len(group.Group.PreferredVersion.Version) != 0 {
|
||||
preferred := group.Group.PreferredVersion.Version
|
||||
if _, ok := group.VersionedResources[preferred]; ok {
|
||||
resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{
|
||||
Group: group.Group.Name,
|
||||
Version: group.Group.PreferredVersion.Version,
|
||||
Resource: meta.AnyResource,
|
||||
})
|
||||
|
||||
kindPriority = append(kindPriority, unversioned.GroupVersionKind{
|
||||
Group: group.Group.Name,
|
||||
Version: group.Group.PreferredVersion.Version,
|
||||
Kind: meta.AnyKind,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, discoveryVersion := range group.Group.Versions {
|
||||
resources, ok := group.VersionedResources[discoveryVersion.Version]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gv := unversioned.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
|
||||
versionMapper := meta.NewDefaultRESTMapper([]unversioned.GroupVersion{gv}, versionInterfaces)
|
||||
|
||||
for _, resource := range resources {
|
||||
scope := meta.RESTScopeNamespace
|
||||
if !resource.Namespaced {
|
||||
scope = meta.RESTScopeRoot
|
||||
}
|
||||
versionMapper.Add(gv.WithKind(resource.Kind), scope)
|
||||
// TODO only do this if it supports listing
|
||||
versionMapper.Add(gv.WithKind(resource.Kind+"List"), scope)
|
||||
}
|
||||
// TODO why is this type not in discovery (at least for "v1")
|
||||
versionMapper.Add(gv.WithKind("List"), meta.RESTScopeRoot)
|
||||
unionMapper = append(unionMapper, versionMapper)
|
||||
}
|
||||
}
|
||||
|
||||
for _, group := range groupPriority {
|
||||
resourcePriority = append(resourcePriority, unversioned.GroupVersionResource{
|
||||
Group: group,
|
||||
Version: meta.AnyVersion,
|
||||
Resource: meta.AnyResource,
|
||||
})
|
||||
kindPriority = append(kindPriority, unversioned.GroupVersionKind{
|
||||
Group: group,
|
||||
Version: meta.AnyVersion,
|
||||
Kind: meta.AnyKind,
|
||||
})
|
||||
}
|
||||
|
||||
return meta.PriorityRESTMapper{
|
||||
Delegate: unionMapper,
|
||||
ResourcePriority: resourcePriority,
|
||||
KindPriority: kindPriority,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAPIGroupResources uses the provided discovery client to gather
|
||||
// discovery information and populate a slice of APIGroupResources.
|
||||
func GetAPIGroupResources(cl DiscoveryInterface) ([]*APIGroupResources, error) {
|
||||
apiGroups, err := cl.ServerGroups()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []*APIGroupResources
|
||||
for _, group := range apiGroups.Groups {
|
||||
groupResources := &APIGroupResources{
|
||||
Group: group,
|
||||
VersionedResources: make(map[string][]unversioned.APIResource),
|
||||
}
|
||||
for _, version := range group.Versions {
|
||||
resources, err := cl.ServerResourcesForGroupVersion(version.GroupVersion)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
continue // ignore as this can race with deletion of 3rd party APIs
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
groupResources.VersionedResources[version.Version] = resources.APIResources
|
||||
}
|
||||
result = append(result, groupResources)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// DeferredDiscoveryRESTMapper is a RESTMapper that will defer
|
||||
// initialization of the RESTMapper until the first mapping is
|
||||
// requested.
|
||||
type DeferredDiscoveryRESTMapper struct {
|
||||
initMu sync.Mutex
|
||||
delegate meta.RESTMapper
|
||||
cl CachedDiscoveryInterface
|
||||
versionInterface meta.VersionInterfacesFunc
|
||||
}
|
||||
|
||||
// NewDeferredDiscoveryRESTMapper returns a
|
||||
// DeferredDiscoveryRESTMapper that will lazily query the provided
|
||||
// client for discovery information to do REST mappings.
|
||||
func NewDeferredDiscoveryRESTMapper(cl CachedDiscoveryInterface, versionInterface meta.VersionInterfacesFunc) *DeferredDiscoveryRESTMapper {
|
||||
return &DeferredDiscoveryRESTMapper{
|
||||
cl: cl,
|
||||
versionInterface: versionInterface,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *DeferredDiscoveryRESTMapper) getDelegate() (meta.RESTMapper, error) {
|
||||
d.initMu.Lock()
|
||||
defer d.initMu.Unlock()
|
||||
|
||||
if d.delegate != nil {
|
||||
return d.delegate, nil
|
||||
}
|
||||
|
||||
groupResources, err := GetAPIGroupResources(d.cl)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
d.delegate = NewRESTMapper(groupResources, d.versionInterface)
|
||||
return d.delegate, err
|
||||
}
|
||||
|
||||
// Reset resets the internally cached Discovery information and will
|
||||
// cause the next mapping request to re-discover.
|
||||
func (d *DeferredDiscoveryRESTMapper) Reset() {
|
||||
glog.V(5).Info("Invalidating discovery information")
|
||||
|
||||
d.initMu.Lock()
|
||||
defer d.initMu.Unlock()
|
||||
|
||||
d.cl.Invalidate()
|
||||
d.delegate = nil
|
||||
}
|
||||
|
||||
// KindFor takes a partial resource and returns back the single match.
|
||||
// It returns an error if there are multiple matches.
|
||||
func (d *DeferredDiscoveryRESTMapper) KindFor(resource unversioned.GroupVersionResource) (gvk unversioned.GroupVersionKind, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return unversioned.GroupVersionKind{}, err
|
||||
}
|
||||
gvk, err = del.KindFor(resource)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvk, err = d.KindFor(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// KindsFor takes a partial resource and returns back the list of
|
||||
// potential kinds in priority order.
|
||||
func (d *DeferredDiscoveryRESTMapper) KindsFor(resource unversioned.GroupVersionResource) (gvks []unversioned.GroupVersionKind, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvks, err = del.KindsFor(resource)
|
||||
if len(gvks) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvks, err = d.KindsFor(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResourceFor takes a partial resource and returns back the single
|
||||
// match. It returns an error if there are multiple matches.
|
||||
func (d *DeferredDiscoveryRESTMapper) ResourceFor(input unversioned.GroupVersionResource) (gvr unversioned.GroupVersionResource, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return unversioned.GroupVersionResource{}, err
|
||||
}
|
||||
gvr, err = del.ResourceFor(input)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvr, err = d.ResourceFor(input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResourcesFor takes a partial resource and returns back the list of
|
||||
// potential resource in priority order.
|
||||
func (d *DeferredDiscoveryRESTMapper) ResourcesFor(input unversioned.GroupVersionResource) (gvrs []unversioned.GroupVersionResource, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gvrs, err = del.ResourcesFor(input)
|
||||
if len(gvrs) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
gvrs, err = d.ResourcesFor(input)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RESTMapping identifies a preferred resource mapping for the
|
||||
// provided group kind.
|
||||
func (d *DeferredDiscoveryRESTMapper) RESTMapping(gk unversioned.GroupKind, versions ...string) (m *meta.RESTMapping, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m, err = del.RESTMapping(gk, versions...)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
m, err = d.RESTMapping(gk, versions...)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// RESTMappings returns the RESTMappings for the provided group kind
|
||||
// in a rough internal preferred order. If no kind is found, it will
|
||||
// return a NoResourceMatchError.
|
||||
func (d *DeferredDiscoveryRESTMapper) RESTMappings(gk unversioned.GroupKind) (ms []*meta.RESTMapping, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ms, err = del.RESTMappings(gk)
|
||||
if len(ms) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
ms, err = d.RESTMappings(gk)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AliasesForResource returns whether a resource has an alias or not.
|
||||
func (d *DeferredDiscoveryRESTMapper) AliasesForResource(resource string) (as []string, ok bool) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
as, ok = del.AliasesForResource(resource)
|
||||
if len(as) == 0 && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
as, ok = d.AliasesForResource(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ResourceSingularizer converts a resource name from plural to
|
||||
// singular (e.g., from pods to pod).
|
||||
func (d *DeferredDiscoveryRESTMapper) ResourceSingularizer(resource string) (singular string, err error) {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return resource, err
|
||||
}
|
||||
singular, err = del.ResourceSingularizer(resource)
|
||||
if err != nil && !d.cl.Fresh() {
|
||||
d.Reset()
|
||||
singular, err = d.ResourceSingularizer(resource)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (d *DeferredDiscoveryRESTMapper) String() string {
|
||||
del, err := d.getDelegate()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("DeferredDiscoveryRESTMapper{%v}", err)
|
||||
}
|
||||
return fmt.Sprintf("DeferredDiscoveryRESTMapper{\n\t%v\n}", del)
|
||||
}
|
||||
|
||||
// Make sure it satisfies the interface
|
||||
var _ meta.RESTMapper = &DeferredDiscoveryRESTMapper{}
|
95
vendor/k8s.io/client-go/discovery/unstructured.go
generated
vendored
Normal file
95
vendor/k8s.io/client-go/discovery/unstructured.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
Copyright 2016 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 discovery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/client-go/pkg/api/unversioned"
|
||||
"k8s.io/client-go/pkg/runtime"
|
||||
)
|
||||
|
||||
// UnstructuredObjectTyper provides a runtime.ObjectTyper implmentation for
|
||||
// runtime.Unstructured object based on discovery information.
|
||||
type UnstructuredObjectTyper struct {
|
||||
registered map[unversioned.GroupVersionKind]bool
|
||||
}
|
||||
|
||||
// NewUnstructuredObjectTyper returns a runtime.ObjectTyper for
|
||||
// unstructred objects based on discovery information.
|
||||
func NewUnstructuredObjectTyper(groupResources []*APIGroupResources) *UnstructuredObjectTyper {
|
||||
dot := &UnstructuredObjectTyper{registered: make(map[unversioned.GroupVersionKind]bool)}
|
||||
for _, group := range groupResources {
|
||||
for _, discoveryVersion := range group.Group.Versions {
|
||||
resources, ok := group.VersionedResources[discoveryVersion.Version]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
gv := unversioned.GroupVersion{Group: group.Group.Name, Version: discoveryVersion.Version}
|
||||
for _, resource := range resources {
|
||||
dot.registered[gv.WithKind(resource.Kind)] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
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) (unversioned.GroupVersionKind, error) {
|
||||
if _, ok := obj.(*runtime.Unstructured); !ok {
|
||||
return unversioned.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 []unversioned.GroupVersionKind, unversionedType bool, err error) {
|
||||
gvk, err := d.ObjectKind(obj)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
return []unversioned.GroupVersionKind{gvk}, false, nil
|
||||
}
|
||||
|
||||
// Recognizes returns true if the provided group,version,kind was in the
|
||||
// discovery information.
|
||||
func (d *UnstructuredObjectTyper) Recognizes(gvk unversioned.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 registered.
|
||||
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{}
|
Loading…
Add table
Add a link
Reference in a new issue