mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 20:17:41 +00:00
Add discovery mapper and dynamic typer to kubectl
This commit is contained in:
parent
3999f071d1
commit
63a512fe47
31
pkg/api/meta/unstructured.go
Normal file
31
pkg/api/meta/unstructured.go
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
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 meta
|
||||
|
||||
import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/runtime"
|
||||
)
|
||||
|
||||
// InterfacesForUnstructured returns VersionInterfaces suitable for
|
||||
// dealing with runtime.Unstructured objects.
|
||||
func InterfacesForUnstructured(unversioned.GroupVersion) (*VersionInterfaces, error) {
|
||||
return &VersionInterfaces{
|
||||
ObjectConvertor: &runtime.UnstructuredObjectConverter{},
|
||||
MetadataAccessor: NewAccessor(),
|
||||
}, nil
|
||||
}
|
95
pkg/client/typed/discovery/unstructured.go
Normal file
95
pkg/client/typed/discovery/unstructured.go
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/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/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{}
|
@ -34,6 +34,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/api/validation"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/fake"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
@ -275,6 +276,13 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec, runtime.Neg
|
||||
Object: func(discovery bool) (meta.RESTMapper, runtime.ObjectTyper) {
|
||||
return testapi.Default.RESTMapper(), api.Scheme
|
||||
},
|
||||
UnstructuredObject: func() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
groupResources := testDynamicResources()
|
||||
mapper := discovery.NewRESTMapper(groupResources, meta.InterfacesForUnstructured)
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
|
||||
return kubectl.ShortcutExpander{RESTMapper: mapper}, typer, nil
|
||||
},
|
||||
Client: func() (*client.Client, error) {
|
||||
// Swap out the HTTP client out of the client with the fake's version.
|
||||
fakeClient := t.Client.(*fake.RESTClient)
|
||||
@ -286,6 +294,9 @@ func NewAPIFactory() (*cmdutil.Factory, *testFactory, runtime.Codec, runtime.Neg
|
||||
ClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||
return t.Client, t.Err
|
||||
},
|
||||
UnstructuredClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||
return t.Client, t.Err
|
||||
},
|
||||
Decoder: func(bool) runtime.Decoder {
|
||||
return testapi.Default.Codec()
|
||||
},
|
||||
|
@ -53,6 +53,8 @@ import (
|
||||
"k8s.io/kubernetes/pkg/apis/policy"
|
||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||
"k8s.io/kubernetes/pkg/client/typed/dynamic"
|
||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||
clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
|
||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
||||
@ -83,6 +85,9 @@ type Factory struct {
|
||||
// Returns interfaces for dealing with arbitrary runtime.Objects. If thirdPartyDiscovery is true, performs API calls
|
||||
// to discovery dynamic API objects registered by third parties.
|
||||
Object func(thirdPartyDiscovery bool) (meta.RESTMapper, runtime.ObjectTyper)
|
||||
// Returns interfaces for dealing with arbitrary
|
||||
// runtime.Unstructured. This performs API calls to discover types.
|
||||
UnstructuredObject func() (meta.RESTMapper, runtime.ObjectTyper, error)
|
||||
// Returns interfaces for decoding objects - if toInternal is set, decoded objects will be converted
|
||||
// into their internal form (if possible). Eventually the internal form will be removed as an option,
|
||||
// and only versioned objects will be returned.
|
||||
@ -96,6 +101,8 @@ type Factory struct {
|
||||
// Returns a RESTClient for working with the specified RESTMapping or an error. This is intended
|
||||
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
||||
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
// Returns a RESTClient for working with Unstructured objects.
|
||||
UnstructuredClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||
Describer func(mapping *meta.RESTMapping) (kubectl.Describer, error)
|
||||
// Returns a Printer for formatting objects of the given type or an error.
|
||||
@ -360,6 +367,40 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
||||
}
|
||||
return priorityRESTMapper, api.Scheme
|
||||
},
|
||||
UnstructuredObject: func() (meta.RESTMapper, runtime.ObjectTyper, error) {
|
||||
cfg, err := clients.ClientConfigForVersion(nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
dc, err := discovery.NewDiscoveryClientForConfig(cfg)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
groupResources, err := discovery.GetAPIGroupResources(dc)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Register unknown APIs as third party for now to make
|
||||
// validation happy. TODO perhaps make a dynamic schema
|
||||
// validator to avoid this.
|
||||
for _, group := range groupResources {
|
||||
for _, version := range group.Group.Versions {
|
||||
gv := unversioned.GroupVersion{Group: group.Group.Name, Version: version.Version}
|
||||
if !registered.IsRegisteredVersion(gv) {
|
||||
registered.AddThirdPartyAPIGroupVersions(gv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapper := discovery.NewRESTMapper(groupResources, meta.InterfacesForUnstructured)
|
||||
|
||||
typer := discovery.NewUnstructuredObjectTyper(groupResources)
|
||||
|
||||
return kubectl.ShortcutExpander{RESTMapper: mapper}, typer, nil
|
||||
},
|
||||
Client: func() (*client.Client, error) {
|
||||
return clients.ClientForVersion(nil)
|
||||
},
|
||||
@ -391,6 +432,23 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
||||
}
|
||||
return restclient.RESTClientFor(cfg)
|
||||
},
|
||||
UnstructuredClientForMapping: func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
||||
cfg, err := clientConfig.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := restclient.SetKubernetesDefaults(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.APIPath = "/apis"
|
||||
if mapping.GroupVersionKind.Group == api.GroupName {
|
||||
cfg.APIPath = "/api"
|
||||
}
|
||||
gv := mapping.GroupVersionKind.GroupVersion()
|
||||
cfg.ContentConfig = dynamic.ContentConfig()
|
||||
cfg.GroupVersion = &gv
|
||||
return restclient.RESTClientFor(cfg)
|
||||
},
|
||||
Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) {
|
||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||
if mapping.GroupVersionKind.Group == federation.GroupName {
|
||||
|
Loading…
Reference in New Issue
Block a user