mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-09 03:57: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/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/api/validation"
|
"k8s.io/kubernetes/pkg/api/validation"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"k8s.io/kubernetes/pkg/client/restclient"
|
||||||
|
"k8s.io/kubernetes/pkg/client/typed/discovery"
|
||||||
client "k8s.io/kubernetes/pkg/client/unversioned"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/fake"
|
"k8s.io/kubernetes/pkg/client/unversioned/fake"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"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) {
|
Object: func(discovery bool) (meta.RESTMapper, runtime.ObjectTyper) {
|
||||||
return testapi.Default.RESTMapper(), api.Scheme
|
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) {
|
Client: func() (*client.Client, error) {
|
||||||
// Swap out the HTTP client out of the client with the fake's version.
|
// Swap out the HTTP client out of the client with the fake's version.
|
||||||
fakeClient := t.Client.(*fake.RESTClient)
|
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) {
|
ClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||||
return t.Client, t.Err
|
return t.Client, t.Err
|
||||||
},
|
},
|
||||||
|
UnstructuredClientForMapping: func(*meta.RESTMapping) (resource.RESTClient, error) {
|
||||||
|
return t.Client, t.Err
|
||||||
|
},
|
||||||
Decoder: func(bool) runtime.Decoder {
|
Decoder: func(bool) runtime.Decoder {
|
||||||
return testapi.Default.Codec()
|
return testapi.Default.Codec()
|
||||||
},
|
},
|
||||||
|
@ -53,6 +53,8 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/apis/policy"
|
"k8s.io/kubernetes/pkg/apis/policy"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/client/restclient"
|
"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"
|
client "k8s.io/kubernetes/pkg/client/unversioned"
|
||||||
clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
|
clientset "k8s.io/kubernetes/pkg/client/unversioned/adapters/internalclientset"
|
||||||
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
|
"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
|
// Returns interfaces for dealing with arbitrary runtime.Objects. If thirdPartyDiscovery is true, performs API calls
|
||||||
// to discovery dynamic API objects registered by third parties.
|
// to discovery dynamic API objects registered by third parties.
|
||||||
Object func(thirdPartyDiscovery bool) (meta.RESTMapper, runtime.ObjectTyper)
|
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
|
// 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,
|
// into their internal form (if possible). Eventually the internal form will be removed as an option,
|
||||||
// and only versioned objects will be returned.
|
// 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
|
// 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.
|
// for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer.
|
||||||
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
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.
|
// Returns a Describer for displaying the specified RESTMapping type or an error.
|
||||||
Describer func(mapping *meta.RESTMapping) (kubectl.Describer, error)
|
Describer func(mapping *meta.RESTMapping) (kubectl.Describer, error)
|
||||||
// Returns a Printer for formatting objects of the given type or an 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
|
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) {
|
Client: func() (*client.Client, error) {
|
||||||
return clients.ClientForVersion(nil)
|
return clients.ClientForVersion(nil)
|
||||||
},
|
},
|
||||||
@ -391,6 +432,23 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
|
|||||||
}
|
}
|
||||||
return restclient.RESTClientFor(cfg)
|
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) {
|
Describer: func(mapping *meta.RESTMapping) (kubectl.Describer, error) {
|
||||||
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
mappingVersion := mapping.GroupVersionKind.GroupVersion()
|
||||||
if mapping.GroupVersionKind.Group == federation.GroupName {
|
if mapping.GroupVersionKind.Group == federation.GroupName {
|
||||||
|
Loading…
Reference in New Issue
Block a user