mirror of https://github.com/k3s-io/k3s
Merge pull request #63446 from deads2k/client-08-remove-old
Automatic merge from submit-queue (batch tested with PRs 63367, 63718, 63446, 63723, 63720). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. finish new dynamic client and deprecate old dynamic client Builds on a couple other pulls. This completes the transition to the new dynamic client. @kubernetes/sig-api-machinery-pr-reviews @caesarxuchao @sttts ```release-note The old dynamic client has been replaced by a new one. The previous dynamic client will exist for one release in `client-go/deprecated-dynamic`. Switch as soon as possible. ```pull/8/head
commit
92ba95c39c
|
@ -33,7 +33,7 @@ import (
|
|||
// ClientBackedDryRunGetter implements the DryRunGetter interface for use in NewDryRunClient() and proxies all GET and LIST requests to the backing API server reachable via rest.Config
|
||||
type ClientBackedDryRunGetter struct {
|
||||
client clientset.Interface
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
dynamicClient dynamic.Interface
|
||||
}
|
||||
|
||||
// InitDryRunGetter should implement the DryRunGetter interface
|
||||
|
|
|
@ -581,6 +581,7 @@ staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/oidc
|
|||
staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest
|
||||
staging/src/k8s.io/apiserver/plugin/pkg/authenticator/token/webhook
|
||||
staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook
|
||||
staging/src/k8s.io/client-go/deprecated-dynamic
|
||||
staging/src/k8s.io/client-go/discovery/cached
|
||||
staging/src/k8s.io/client-go/dynamic
|
||||
staging/src/k8s.io/client-go/dynamic/fake
|
||||
|
|
|
@ -60,7 +60,7 @@ const ResourceResyncTime time.Duration = 0
|
|||
// up to date as the notification is sent.
|
||||
type GarbageCollector struct {
|
||||
restMapper resettableRESTMapper
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
dynamicClient dynamic.Interface
|
||||
// garbage collector attempts to delete the items in attemptToDelete queue when the time is ripe.
|
||||
attemptToDelete workqueue.RateLimitingInterface
|
||||
// garbage collector attempts to orphan the dependents of the items in the attemptToOrphan queue, then deletes the items.
|
||||
|
@ -74,7 +74,7 @@ type GarbageCollector struct {
|
|||
}
|
||||
|
||||
func NewGarbageCollector(
|
||||
dynamicClient dynamic.DynamicInterface,
|
||||
dynamicClient dynamic.Interface,
|
||||
mapper resettableRESTMapper,
|
||||
deletableResources map[schema.GroupVersionResource]struct{},
|
||||
ignoredResources map[schema.GroupResource]struct{},
|
||||
|
|
|
@ -91,10 +91,7 @@ type GraphBuilder struct {
|
|||
// it is protected by monitorLock.
|
||||
running bool
|
||||
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
// metaOnlyClientPool uses a special codec, which removes fields except for
|
||||
// apiVersion, kind, and metadata during decoding.
|
||||
metaOnlyClientPool dynamic.ClientPool
|
||||
dynamicClient dynamic.Interface
|
||||
// monitors are the producer of the graphChanges queue, graphBuilder alters
|
||||
// the in-memory graph according to the changes.
|
||||
graphChanges workqueue.RateLimitingInterface
|
||||
|
@ -128,7 +125,7 @@ func (m *monitor) Run() {
|
|||
|
||||
type monitors map[schema.GroupVersionResource]*monitor
|
||||
|
||||
func listWatcher(client dynamic.DynamicInterface, resource schema.GroupVersionResource) *cache.ListWatch {
|
||||
func listWatcher(client dynamic.Interface, resource schema.GroupVersionResource) *cache.ListWatch {
|
||||
return &cache.ListWatch{
|
||||
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
|
||||
// We want to list this resource in all namespaces if it's namespace scoped, so not passing namespace is ok.
|
||||
|
|
|
@ -43,7 +43,7 @@ type NamespacedResourcesDeleterInterface interface {
|
|||
}
|
||||
|
||||
func NewNamespacedResourcesDeleter(nsClient v1clientset.NamespaceInterface,
|
||||
dynamicClient dynamic.DynamicInterface, podsGetter v1clientset.PodsGetter,
|
||||
dynamicClient dynamic.Interface, podsGetter v1clientset.PodsGetter,
|
||||
discoverResourcesFn func() ([]*metav1.APIResourceList, error),
|
||||
finalizerToken v1.FinalizerName, deleteNamespaceWhenDone bool) NamespacedResourcesDeleterInterface {
|
||||
d := &namespacedResourcesDeleter{
|
||||
|
@ -68,7 +68,7 @@ type namespacedResourcesDeleter struct {
|
|||
// Client to manipulate the namespace.
|
||||
nsClient v1clientset.NamespaceInterface
|
||||
// Dynamic client to list and delete all namespaced resources.
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
dynamicClient dynamic.Interface
|
||||
// Interface to get PodInterface.
|
||||
podsGetter v1clientset.PodsGetter
|
||||
// Cache of what operations are not supported on each group version resource.
|
||||
|
|
|
@ -63,7 +63,7 @@ type NamespaceController struct {
|
|||
// NewNamespaceController creates a new NamespaceController
|
||||
func NewNamespaceController(
|
||||
kubeClient clientset.Interface,
|
||||
dynamicClient dynamic.DynamicInterface,
|
||||
dynamicClient dynamic.Interface,
|
||||
discoverResourcesFn func() ([]*metav1.APIResourceList, error),
|
||||
namespaceInformer coreinformers.NamespaceInformer,
|
||||
resyncPeriod time.Duration,
|
||||
|
|
|
@ -226,7 +226,6 @@ go_test(
|
|||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch/testing:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/scale/fake:go_default_library",
|
||||
|
|
|
@ -82,7 +82,7 @@ type ApplyOptions struct {
|
|||
Builder *resource.Builder
|
||||
Mapper meta.RESTMapper
|
||||
Scaler scaleclient.ScalesGetter
|
||||
DynamicClient dynamic.DynamicInterface
|
||||
DynamicClient dynamic.Interface
|
||||
ClientSetFunc func() (internalclientset.Interface, error)
|
||||
OpenAPISchema openapi.Resources
|
||||
|
||||
|
@ -580,7 +580,7 @@ func getRESTMappings(mapper meta.RESTMapper, pruneResources *[]pruneResource) (n
|
|||
|
||||
type pruner struct {
|
||||
mapper meta.RESTMapper
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
dynamicClient dynamic.Interface
|
||||
clientsetFunc func() (internalclientset.Interface, error)
|
||||
|
||||
visitedUids sets.String
|
||||
|
@ -649,7 +649,7 @@ func (p *pruner) delete(namespace, name string, mapping *meta.RESTMapping, scale
|
|||
return runDelete(namespace, name, mapping, p.dynamicClient, p.cascade, p.gracePeriod, p.clientsetFunc, scaleClient)
|
||||
}
|
||||
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.DynamicInterface, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error), scaleClient scaleclient.ScalesGetter) error {
|
||||
func runDelete(namespace, name string, mapping *meta.RESTMapping, c dynamic.Interface, cascade bool, gracePeriod int, clientsetFunc func() (internalclientset.Interface, error), scaleClient scaleclient.ScalesGetter) error {
|
||||
if !cascade {
|
||||
return c.Resource(mapping.Resource).Namespace(namespace).Delete(name, nil)
|
||||
}
|
||||
|
@ -681,7 +681,7 @@ func (p *patcher) delete(namespace, name string) error {
|
|||
type patcher struct {
|
||||
mapping *meta.RESTMapping
|
||||
helper *resource.Helper
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
dynamicClient dynamic.Interface
|
||||
clientsetFunc func() (internalclientset.Interface, error)
|
||||
|
||||
overwrite bool
|
||||
|
|
|
@ -82,6 +82,7 @@ go_test(
|
|||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/k8s.io/api/batch/v1:go_default_library",
|
||||
|
@ -94,7 +95,6 @@ go_test(
|
|||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
|
||||
|
|
|
@ -348,7 +348,7 @@ type CreateSubcommandOptions struct {
|
|||
EnforceNamespace bool
|
||||
|
||||
Mapper meta.RESTMapper
|
||||
DynamicClient dynamic.DynamicInterface
|
||||
DynamicClient dynamic.Interface
|
||||
|
||||
PrintObj func(obj kruntime.Object) error
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
|
@ -30,6 +29,7 @@ import (
|
|||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
|
@ -158,7 +158,7 @@ func TestCreateDirectory(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
func initTestErrorHandler(t *testing.T) {
|
||||
cmdutil.BehaviorOnFatal(func(str string, code int) {
|
||||
|
|
|
@ -30,7 +30,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
api "k8s.io/kubernetes/pkg/apis/core"
|
||||
|
@ -42,7 +41,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
func fakecmd() *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
|
|
|
@ -100,7 +100,7 @@ type ExposeServiceOptions struct {
|
|||
Namespace string
|
||||
Mapper meta.RESTMapper
|
||||
|
||||
DynamicClient dynamic.DynamicInterface
|
||||
DynamicClient dynamic.Interface
|
||||
Builder *resource.Builder
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
|
|
|
@ -75,6 +75,7 @@ go_test(
|
|||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi/testing:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions:go_default_library",
|
||||
"//pkg/kubectl/genericclioptions/resource:go_default_library",
|
||||
"//pkg/kubectl/scheme:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
|
@ -85,7 +86,6 @@ go_test(
|
|||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/fake:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/watch:go_default_library",
|
||||
|
|
|
@ -34,7 +34,6 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/serializer/json"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
|
@ -49,6 +48,7 @@ import (
|
|||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
openapitesting "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
|
||||
"k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
|
@ -61,7 +61,7 @@ func init() {
|
|||
scheme.Scheme.AddConversionFuncs(v1.Convert_v1_PodSecurityContext_To_core_PodSecurityContext)
|
||||
}
|
||||
|
||||
var unstructuredSerializer = dynamic.ContentConfig().NegotiatedSerializer
|
||||
var unstructuredSerializer = resource.UnstructuredPlusDefaultContentConfig().NegotiatedSerializer
|
||||
|
||||
func defaultHeader() http.Header {
|
||||
header := http.Header{}
|
||||
|
|
|
@ -107,7 +107,7 @@ type RunOptions struct {
|
|||
PrintObj func(runtime.Object) error
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
DynamicClient dynamic.DynamicInterface
|
||||
DynamicClient dynamic.Interface
|
||||
|
||||
ArgsLenAtDash int
|
||||
Attach bool
|
||||
|
|
|
@ -398,7 +398,7 @@ func (f *TestFactory) ClientSet() (internalclientset.Interface, error) {
|
|||
return clientset, nil
|
||||
}
|
||||
|
||||
func (f *TestFactory) DynamicClient() (dynamic.DynamicInterface, error) {
|
||||
func (f *TestFactory) DynamicClient() (dynamic.Interface, error) {
|
||||
if f.FakeDynamicClient != nil {
|
||||
return f.FakeDynamicClient, nil
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ type ClientAccessFactory interface {
|
|||
ClientSet() (internalclientset.Interface, error)
|
||||
|
||||
// DynamicClient returns a dynamic client ready for use
|
||||
DynamicClient() (dynamic.DynamicInterface, error)
|
||||
DynamicClient() (dynamic.Interface, error)
|
||||
|
||||
// KubernetesClientSet gives you back an external clientset
|
||||
KubernetesClientSet() (*kubernetes.Clientset, error)
|
||||
|
|
|
@ -114,7 +114,7 @@ func (f *ring0Factory) ClientSet() (internalclientset.Interface, error) {
|
|||
return internalclientset.NewForConfig(clientConfig)
|
||||
}
|
||||
|
||||
func (f *ring0Factory) DynamicClient() (dynamic.DynamicInterface, error) {
|
||||
func (f *ring0Factory) DynamicClient() (dynamic.Interface, error) {
|
||||
clientConfig, err := f.ClientConfig()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -117,7 +117,7 @@ func (f *ring1Factory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (
|
|||
cfg.APIPath = "/api"
|
||||
}
|
||||
gv := mapping.GroupVersionKind.GroupVersion()
|
||||
cfg.ContentConfig = dynamic.ContentConfig()
|
||||
cfg.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
|
||||
cfg.GroupVersion = &gv
|
||||
return restclient.RESTClientFor(cfg)
|
||||
}
|
||||
|
@ -146,13 +146,8 @@ func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RES
|
|||
return nil, err
|
||||
}
|
||||
|
||||
clientConfigCopy := *clientConfig
|
||||
clientConfigCopy.APIPath = dynamic.LegacyAPIPathResolverFunc(mapping.GroupVersionKind)
|
||||
gv := mapping.GroupVersionKind.GroupVersion()
|
||||
clientConfigCopy.GroupVersion = &gv
|
||||
|
||||
// used to fetch the resource
|
||||
dynamicClient, err := dynamic.NewClient(&clientConfigCopy, gv)
|
||||
dynamicClient, err := dynamic.NewForConfig(clientConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ go_library(
|
|||
"interfaces.go",
|
||||
"mapper.go",
|
||||
"result.go",
|
||||
"scheme.go",
|
||||
"selector.go",
|
||||
"visitor.go",
|
||||
],
|
||||
|
@ -36,7 +37,7 @@ go_library(
|
|||
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/discovery:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/restmapper:go_default_library",
|
||||
],
|
||||
|
|
|
@ -19,7 +19,6 @@ package resource
|
|||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
|
@ -47,7 +46,7 @@ func (clientConfigFn ClientConfigFunc) unstructuredClientForGroupVersion(gv sche
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.ContentConfig = dynamic.ContentConfig()
|
||||
cfg.ContentConfig = UnstructuredPlusDefaultContentConfig()
|
||||
cfg.GroupVersion = &gv
|
||||
if len(gv.Group) == 0 {
|
||||
cfg.APIPath = "/api"
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
Copyright 2018 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 resource
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// dynamicCodec is a codec that wraps the standard unstructured codec
|
||||
// with special handling for Status objects.
|
||||
// Deprecated only used by test code and its wrong
|
||||
type dynamicCodec struct{}
|
||||
|
||||
func (dynamicCodec) Decode(data []byte, gvk *schema.GroupVersionKind, obj runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
|
||||
obj, gvk, err := unstructured.UnstructuredJSONScheme.Decode(data, gvk, obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if _, ok := obj.(*metav1.Status); !ok && strings.ToLower(gvk.Kind) == "status" {
|
||||
obj = &metav1.Status{}
|
||||
err := json.Unmarshal(data, obj)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return obj, gvk, nil
|
||||
}
|
||||
|
||||
func (dynamicCodec) Encode(obj runtime.Object, w io.Writer) error {
|
||||
return unstructured.UnstructuredJSONScheme.Encode(obj, w)
|
||||
}
|
||||
|
||||
// ContentConfig returns a rest.ContentConfig for dynamic types. It includes enough codecs to act as a "normal"
|
||||
// serializer for the rest.client with options, status and the like.
|
||||
func UnstructuredPlusDefaultContentConfig() rest.ContentConfig {
|
||||
var jsonInfo runtime.SerializerInfo
|
||||
// TODO: scheme.Codecs here should become "pkg/apis/server/scheme" which is the minimal core you need
|
||||
// to talk to a kubernetes server
|
||||
for _, info := range scheme.Codecs.SupportedMediaTypes() {
|
||||
if info.MediaType == runtime.ContentTypeJSON {
|
||||
jsonInfo = info
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
jsonInfo.Serializer = dynamicCodec{}
|
||||
jsonInfo.PrettySerializer = nil
|
||||
return rest.ContentConfig{
|
||||
AcceptContentTypes: runtime.ContentTypeJSON,
|
||||
ContentType: runtime.ContentTypeJSON,
|
||||
NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(jsonInfo),
|
||||
}
|
||||
}
|
|
@ -203,12 +203,7 @@ type genericDescriber struct {
|
|||
}
|
||||
|
||||
func (g *genericDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) {
|
||||
apiResource := &metav1.APIResource{
|
||||
Name: g.mapping.Resource.Resource,
|
||||
Namespaced: g.mapping.Scope.Name() == meta.RESTScopeNameNamespace,
|
||||
Kind: g.mapping.GroupVersionKind.Kind,
|
||||
}
|
||||
obj, err := g.dynamic.Resource(apiResource, namespace).Get(name, metav1.GetOptions{})
|
||||
obj, err := g.dynamic.Resource(g.mapping.Resource).Namespace(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ filegroup(
|
|||
"//staging/src/k8s.io/apiserver/plugin/pkg/audit:all-srcs",
|
||||
"//staging/src/k8s.io/apiserver/plugin/pkg/authenticator:all-srcs",
|
||||
"//staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook:all-srcs",
|
||||
"//staging/src/k8s.io/client-go/deprecated-dynamic:all-srcs",
|
||||
"//staging/src/k8s.io/client-go/discovery:all-srcs",
|
||||
"//staging/src/k8s.io/client-go/dynamic:all-srcs",
|
||||
"//staging/src/k8s.io/client-go/examples/create-update-delete-deployment:all-srcs",
|
||||
|
|
|
@ -80,7 +80,7 @@ func TestClusterScopedCRUD(t *testing.T) {
|
|||
testFieldSelector(t, ns, noxuDefinition, dynamicClient)
|
||||
}
|
||||
|
||||
func testSimpleCRUD(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition, dynamicClient dynamic.DynamicInterface) {
|
||||
func testSimpleCRUD(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition, dynamicClient dynamic.Interface) {
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
initialList, err := noxuResourceClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
|
@ -202,7 +202,7 @@ func testSimpleCRUD(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta
|
|||
}
|
||||
}
|
||||
|
||||
func testFieldSelector(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition, dynamicClient dynamic.DynamicInterface) {
|
||||
func testFieldSelector(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition, dynamicClient dynamic.Interface) {
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
initialList, err := noxuResourceClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
|
@ -704,7 +704,7 @@ func TestCrossNamespaceListWatch(t *testing.T) {
|
|||
checkNamespacesWatchHelper(t, ns2, noxuNamespacesWatch2)
|
||||
}
|
||||
|
||||
func createInstanceWithNamespaceHelper(t *testing.T, ns string, name string, noxuNamespacedResourceClient dynamic.DynamicResourceInterface, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition) *unstructured.Unstructured {
|
||||
func createInstanceWithNamespaceHelper(t *testing.T, ns string, name string, noxuNamespacedResourceClient dynamic.ResourceInterface, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition) *unstructured.Unstructured {
|
||||
createdInstance, err := instantiateCustomResource(t, testserver.NewNoxuInstance(ns, name), noxuNamespacedResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu Instance:%v", err)
|
||||
|
|
|
@ -41,7 +41,7 @@ import (
|
|||
"k8s.io/client-go/dynamic"
|
||||
)
|
||||
|
||||
func instantiateCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.DynamicResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
|
||||
func instantiateCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
|
||||
createdInstance, err := client.Create(instanceToCreate)
|
||||
if err != nil {
|
||||
t.Logf("%#v", createdInstance)
|
||||
|
@ -68,7 +68,7 @@ func instantiateCustomResource(t *testing.T, instanceToCreate *unstructured.Unst
|
|||
return createdInstance, nil
|
||||
}
|
||||
|
||||
func NewNamespacedCustomResourceClient(ns string, client dynamic.DynamicInterface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.DynamicResourceInterface {
|
||||
func NewNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.ResourceInterface {
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural}
|
||||
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
|
@ -77,24 +77,6 @@ func NewNamespacedCustomResourceClient(ns string, client dynamic.DynamicInterfac
|
|||
return client.Resource(gvr)
|
||||
}
|
||||
|
||||
func NewNamespacedCustomResourceStatusClient(ns string, client dynamic.DynamicInterface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.DynamicResourceInterface {
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural}
|
||||
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
return client.NamespacedSubresource(gvr, "status", ns)
|
||||
}
|
||||
return client.ClusterSubresource(gvr, "status")
|
||||
}
|
||||
|
||||
func NewNamespacedCustomResourceScaleClient(ns string, client dynamic.DynamicInterface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.DynamicResourceInterface {
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural}
|
||||
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
return client.NamespacedSubresource(gvr, "scale", ns)
|
||||
}
|
||||
return client.ClusterSubresource(gvr, "scale")
|
||||
}
|
||||
|
||||
func TestMultipleResourceInstances(t *testing.T) {
|
||||
stopCh, apiExtensionClient, dynamicClient, err := testserver.StartDefaultServerWithClients()
|
||||
if err != nil {
|
||||
|
|
|
@ -105,7 +105,6 @@ func TestStatusSubresource(t *testing.T) {
|
|||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
noxuStatusResourceClient := NewNamespacedCustomResourceStatusClient(ns, dynamicClient, noxuDefinition)
|
||||
_, err = instantiateCustomResource(t, NewNoxuSubresourceInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu instance: %v", err)
|
||||
|
@ -135,7 +134,7 @@ func TestStatusSubresource(t *testing.T) {
|
|||
|
||||
// UpdateStatus should not update spec.
|
||||
// Check that .spec.num = 10 and .status.num = 20
|
||||
updatedStatusInstance, err := noxuStatusResourceClient.Update(gottenNoxuInstance)
|
||||
updatedStatusInstance, err := noxuResourceClient.UpdateStatus(gottenNoxuInstance)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to update status: %v", err)
|
||||
}
|
||||
|
@ -238,7 +237,6 @@ func TestScaleSubresource(t *testing.T) {
|
|||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
noxuStatusResourceClient := NewNamespacedCustomResourceStatusClient(ns, dynamicClient, noxuDefinition)
|
||||
_, err = instantiateCustomResource(t, NewNoxuSubresourceInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu instance: %v", err)
|
||||
|
@ -258,7 +256,7 @@ func TestScaleSubresource(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
_, err = noxuStatusResourceClient.Update(gottenNoxuInstance)
|
||||
_, err = noxuResourceClient.UpdateStatus(gottenNoxuInstance)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to update status: %v", err)
|
||||
}
|
||||
|
@ -430,7 +428,6 @@ func TestValidateOnlyStatus(t *testing.T) {
|
|||
}
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
noxuStatusResourceClient := NewNamespacedCustomResourceStatusClient(ns, dynamicClient, noxuDefinition)
|
||||
|
||||
// set .spec.num = 10 and .status.num = 10
|
||||
noxuInstance := NewNoxuSubresourceInstance(ns, "foo")
|
||||
|
@ -449,7 +446,7 @@ func TestValidateOnlyStatus(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error setting .spec.num: %v", err)
|
||||
}
|
||||
createdNoxuInstance, err = noxuStatusResourceClient.Update(createdNoxuInstance)
|
||||
createdNoxuInstance, err = noxuResourceClient.UpdateStatus(createdNoxuInstance)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -459,7 +456,7 @@ func TestValidateOnlyStatus(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("unexpected error setting .status.num: %v", err)
|
||||
}
|
||||
createdNoxuInstance, err = noxuStatusResourceClient.Update(createdNoxuInstance)
|
||||
createdNoxuInstance, err = noxuResourceClient.UpdateStatus(createdNoxuInstance)
|
||||
if err == nil {
|
||||
t.Fatal("expected error, but got none")
|
||||
}
|
||||
|
@ -577,7 +574,6 @@ func TestGeneration(t *testing.T) {
|
|||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
noxuStatusResourceClient := NewNamespacedCustomResourceStatusClient(ns, dynamicClient, noxuDefinition)
|
||||
_, err = instantiateCustomResource(t, NewNoxuSubresourceInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu instance: %v", err)
|
||||
|
@ -599,7 +595,7 @@ func TestGeneration(t *testing.T) {
|
|||
}
|
||||
|
||||
// UpdateStatus does not increment generation
|
||||
updatedStatusInstance, err := noxuStatusResourceClient.Update(gottenNoxuInstance)
|
||||
updatedStatusInstance, err := noxuResourceClient.UpdateStatus(gottenNoxuInstance)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to update status: %v", err)
|
||||
}
|
||||
|
@ -660,8 +656,6 @@ func TestSubresourcePatch(t *testing.T) {
|
|||
|
||||
ns := "not-the-default"
|
||||
noxuResourceClient := NewNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
|
||||
noxuStatusResourceClient := NewNamespacedCustomResourceStatusClient(ns, dynamicClient, noxuDefinition)
|
||||
noxuScaleResourceClient := NewNamespacedCustomResourceScaleClient(ns, dynamicClient, noxuDefinition)
|
||||
_, err = instantiateCustomResource(t, NewNoxuSubresourceInstance(ns, "foo"), noxuResourceClient, noxuDefinition)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create noxu instance: %v", err)
|
||||
|
@ -673,7 +667,7 @@ func TestSubresourcePatch(t *testing.T) {
|
|||
}
|
||||
|
||||
patch := []byte(`{"spec": {"num":999}, "status": {"num":999}}`)
|
||||
patchedNoxuInstance, err := noxuStatusResourceClient.Patch("foo", types.MergePatchType, patch)
|
||||
patchedNoxuInstance, err := noxuResourceClient.Patch("foo", types.MergePatchType, patch, "status")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -708,19 +702,19 @@ func TestSubresourcePatch(t *testing.T) {
|
|||
}
|
||||
|
||||
// no-op patch
|
||||
_, err = noxuStatusResourceClient.Patch("foo", types.MergePatchType, patch)
|
||||
_, err = noxuResourceClient.Patch("foo", types.MergePatchType, patch, "status")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// empty patch
|
||||
_, err = noxuStatusResourceClient.Patch("foo", types.MergePatchType, []byte(`{}`))
|
||||
_, err = noxuResourceClient.Patch("foo", types.MergePatchType, []byte(`{}`), "status")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
patch = []byte(`{"spec": {"replicas":7}, "status": {"replicas":7}}`)
|
||||
patchedNoxuInstance, err = noxuScaleResourceClient.Patch("foo", types.MergePatchType, patch)
|
||||
patchedNoxuInstance, err = noxuResourceClient.Patch("foo", types.MergePatchType, patch, "scale")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
@ -749,24 +743,24 @@ func TestSubresourcePatch(t *testing.T) {
|
|||
}
|
||||
|
||||
// no-op patch
|
||||
_, err = noxuScaleResourceClient.Patch("foo", types.MergePatchType, patch)
|
||||
_, err = noxuResourceClient.Patch("foo", types.MergePatchType, patch, "scale")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// empty patch
|
||||
_, err = noxuScaleResourceClient.Patch("foo", types.MergePatchType, []byte(`{}`))
|
||||
_, err = noxuResourceClient.Patch("foo", types.MergePatchType, []byte(`{}`), "scale")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// make sure strategic merge patch is not supported for both status and scale
|
||||
_, err = noxuStatusResourceClient.Patch("foo", types.StrategicMergePatchType, patch)
|
||||
_, err = noxuResourceClient.Patch("foo", types.StrategicMergePatchType, patch, "status")
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error: strategic merge patch is not supported for custom resources")
|
||||
}
|
||||
|
||||
_, err = noxuScaleResourceClient.Patch("foo", types.StrategicMergePatchType, patch)
|
||||
_, err = noxuResourceClient.Patch("foo", types.StrategicMergePatchType, patch, "scale")
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected non-error: strategic merge patch is not supported for custom resources")
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ func CreateNewCustomResourceDefinitionWatchUnsafe(crd *apiextensionsv1beta1.Cust
|
|||
return err
|
||||
}
|
||||
|
||||
func CreateNewCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceDefinition, apiExtensionsClient clientset.Interface, dynamicClientSet dynamic.DynamicInterface) error {
|
||||
func CreateNewCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceDefinition, apiExtensionsClient clientset.Interface, dynamicClientSet dynamic.Interface) error {
|
||||
err := CreateNewCustomResourceDefinitionWatchUnsafe(crd, apiExtensionsClient)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -209,14 +209,14 @@ func CreateNewCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceD
|
|||
return nil
|
||||
}
|
||||
|
||||
func checkForWatchCachePrimed(crd *apiextensionsv1beta1.CustomResourceDefinition, dynamicClientSet dynamic.DynamicInterface) error {
|
||||
func checkForWatchCachePrimed(crd *apiextensionsv1beta1.CustomResourceDefinition, dynamicClientSet dynamic.Interface) error {
|
||||
ns := ""
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
ns = "aval"
|
||||
}
|
||||
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural}
|
||||
var resourceClient dynamic.DynamicResourceInterface
|
||||
var resourceClient dynamic.ResourceInterface
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
resourceClient = dynamicClientSet.Resource(gvr).Namespace(ns)
|
||||
} else {
|
||||
|
|
|
@ -139,7 +139,7 @@ func StartDefaultServer() (chan struct{}, *rest.Config, error) {
|
|||
return StartServer(config)
|
||||
}
|
||||
|
||||
func StartDefaultServerWithClients() (chan struct{}, clientset.Interface, dynamic.DynamicInterface, error) {
|
||||
func StartDefaultServerWithClients() (chan struct{}, clientset.Interface, dynamic.Interface, error) {
|
||||
stopCh, config, err := StartDefaultServer()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"bad_debt.go",
|
||||
"client.go",
|
||||
"client_pool.go",
|
||||
],
|
||||
importpath = "k8s.io/client-go/deprecated-dynamic",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["client_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest/watch:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dynamic
|
||||
package deprecated_dynamic
|
||||
|
||||
import (
|
||||
"encoding/json"
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
|||
// Package dynamic provides a client interface to arbitrary Kubernetes
|
||||
// APIs that exposes common high level operations and exposes common
|
||||
// metadata.
|
||||
package dynamic
|
||||
package deprecated_dynamic
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
@ -28,6 +28,7 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
|
@ -65,13 +66,13 @@ type ResourceInterface interface {
|
|||
// and manipulate metadata of a Kubernetes API group, and implements Interface.
|
||||
type Client struct {
|
||||
version schema.GroupVersion
|
||||
delegate DynamicInterface
|
||||
delegate dynamic.Interface
|
||||
}
|
||||
|
||||
// NewClient returns a new client based on the passed in config. The
|
||||
// codec is ignored, as the dynamic client uses it's own codec.
|
||||
func NewClient(conf *restclient.Config, version schema.GroupVersion) (*Client, error) {
|
||||
delegate, err := NewForConfig(conf)
|
||||
delegate, err := dynamic.NewForConfig(conf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -84,30 +85,47 @@ func NewClient(conf *restclient.Config, version schema.GroupVersion) (*Client, e
|
|||
// is ignored. The ResourceInterface inherits the parameter codec of c.
|
||||
func (c *Client) Resource(resource *metav1.APIResource, namespace string) ResourceInterface {
|
||||
resourceTokens := strings.SplitN(resource.Name, "/", 2)
|
||||
subresource := ""
|
||||
subresources := []string{}
|
||||
if len(resourceTokens) > 1 {
|
||||
subresource = resourceTokens[1]
|
||||
subresources = strings.Split(resourceTokens[1], "/")
|
||||
}
|
||||
|
||||
if len(namespace) == 0 {
|
||||
return oldResourceShim(c.delegate.ClusterSubresource(c.version.WithResource(resourceTokens[0]), subresource))
|
||||
return oldResourceShim(c.delegate.Resource(c.version.WithResource(resourceTokens[0])), subresources)
|
||||
}
|
||||
return oldResourceShim(c.delegate.NamespacedSubresource(c.version.WithResource(resourceTokens[0]), subresource, namespace))
|
||||
return oldResourceShim(c.delegate.Resource(c.version.WithResource(resourceTokens[0])).Namespace(namespace), subresources)
|
||||
}
|
||||
|
||||
// the old interfaces used the wrong type for lists. this fixes that
|
||||
func oldResourceShim(in DynamicResourceInterface) ResourceInterface {
|
||||
return oldResourceShimType{DynamicResourceInterface: in}
|
||||
func oldResourceShim(in dynamic.ResourceInterface, subresources []string) ResourceInterface {
|
||||
return oldResourceShimType{ResourceInterface: in, subresources: subresources}
|
||||
}
|
||||
|
||||
type oldResourceShimType struct {
|
||||
DynamicResourceInterface
|
||||
dynamic.ResourceInterface
|
||||
subresources []string
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Create(obj, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Update(obj, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
return s.ResourceInterface.Delete(name, opts, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
|
||||
return s.ResourceInterface.Get(name, opts, s.subresources...)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) List(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
return s.DynamicResourceInterface.List(opts)
|
||||
return s.ResourceInterface.List(opts)
|
||||
}
|
||||
|
||||
func (s oldResourceShimType) Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) {
|
||||
return s.DynamicResourceInterface.Patch(name, pt, data)
|
||||
return s.ResourceInterface.Patch(name, pt, data, s.subresources...)
|
||||
}
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package dynamic
|
||||
package deprecated_dynamic
|
||||
|
||||
import (
|
||||
"sync"
|
|
@ -0,0 +1,623 @@
|
|||
/*
|
||||
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 deprecated_dynamic
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
restclientwatch "k8s.io/client-go/rest/watch"
|
||||
)
|
||||
|
||||
func getJSON(version, kind, name string) []byte {
|
||||
return []byte(fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "metadata": {"name": %q}}`, version, kind, name))
|
||||
}
|
||||
|
||||
func getListJSON(version, kind string, items ...[]byte) []byte {
|
||||
json := fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "items": [%s]}`,
|
||||
version, kind, bytes.Join(items, []byte(",")))
|
||||
return []byte(json)
|
||||
}
|
||||
|
||||
func getObject(version, kind, name string) *unstructured.Unstructured {
|
||||
return &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": version,
|
||||
"kind": kind,
|
||||
"metadata": map[string]interface{}{
|
||||
"name": name,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func getClientServer(gv *schema.GroupVersion, h func(http.ResponseWriter, *http.Request)) (Interface, *httptest.Server, error) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(h))
|
||||
cl, err := NewClient(&restclient.Config{
|
||||
Host: srv.URL,
|
||||
ContentConfig: restclient.ContentConfig{GroupVersion: gv},
|
||||
}, *gv)
|
||||
if err != nil {
|
||||
srv.Close()
|
||||
return nil, nil, err
|
||||
}
|
||||
return cl, srv, nil
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.UnstructuredList
|
||||
}{
|
||||
{
|
||||
name: "normal_list",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
resp: getListJSON("vTest", "rTestList",
|
||||
getJSON("vTest", "rTest", "item1"),
|
||||
getJSON("vTest", "rTest", "item2")),
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "vTest",
|
||||
"kind": "rTestList",
|
||||
},
|
||||
Items: []unstructured.Unstructured{
|
||||
*getObject("vTest", "rTest", "item1"),
|
||||
*getObject("vTest", "rTest", "item2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namespaced_list",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
resp: getListJSON("vTest", "rTestList",
|
||||
getJSON("vTest", "rTest", "item1"),
|
||||
getJSON("vTest", "rTest", "item2")),
|
||||
want: &unstructured.UnstructuredList{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "vTest",
|
||||
"kind": "rTestList",
|
||||
},
|
||||
Items: []unstructured.Unstructured{
|
||||
*getObject("vTest", "rTest", "item1"),
|
||||
*getObject("vTest", "rTest", "item2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("List(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("List(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Write(tc.resp)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when listing %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("List(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.Unstructured
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_get",
|
||||
path: "/apis/gtest/vtest/rtest/normal_get",
|
||||
resp: getJSON("vTest", "rTest", "normal_get"),
|
||||
want: getObject("vTest", "rTest", "normal_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
namespace: "nstest",
|
||||
name: "namespaced_get",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_get",
|
||||
resp: getJSON("vTest", "rTest", "namespaced_get"),
|
||||
want: getObject("vTest", "rTest", "namespaced_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_get",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "normal_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "normal_subresource_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
namespace: "nstest",
|
||||
name: "namespaced_subresource_get",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "namespaced_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "namespaced_subresource_get"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Get(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Get(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
w.Write(tc.resp)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Get(tc.name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when getting %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Get(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDelete(t *testing.T) {
|
||||
background := metav1.DeletePropagationBackground
|
||||
uid := types.UID("uid")
|
||||
|
||||
statusOK := &metav1.Status{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Status"},
|
||||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
deleteOptions *metav1.DeleteOptions
|
||||
}{
|
||||
{
|
||||
name: "normal_delete",
|
||||
path: "/apis/gtest/vtest/rtest/normal_delete",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete_with_options",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete_with_options",
|
||||
deleteOptions: &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}, PropagationPolicy: &background},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("Delete(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Delete(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
unstructured.UnstructuredJSONScheme.Encode(statusOK, w)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).Delete(tc.name, tc.deleteOptions)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteCollection(t *testing.T) {
|
||||
statusOK := &metav1.Status{
|
||||
TypeMeta: metav1.TypeMeta{Kind: "Status"},
|
||||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
}{
|
||||
{
|
||||
name: "normal_delete_collection",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete_collection",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("DeleteCollection(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("DeleteCollection(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
unstructured.UnstructuredJSONScheme.Encode(statusOK, w)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).DeleteCollection(nil, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting collection %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_create",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
obj: getObject("gtest/vTest", "rTest", "normal_create"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "namespaced_create",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
obj: getObject("gtest/vTest", "rTest", "namespaced_create"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("Create(%q) got HTTP method %s. wanted POST", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Create(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Create(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Create(tc.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.obj) {
|
||||
t.Errorf("Create(%q) want: %v\ngot: %v", tc.name, tc.obj, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_update",
|
||||
path: "/apis/gtest/vtest/rtest/normal_update",
|
||||
obj: getObject("gtest/vTest", "rTest", "normal_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "namespaced_update",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update",
|
||||
obj: getObject("gtest/vTest", "rTest", "namespaced_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_update",
|
||||
path: "/apis/gtest/vtest/rtest/normal_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "normal_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "namespaced_subresource_update",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "namespaced_update"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PUT" {
|
||||
t.Errorf("Update(%q) got HTTP method %s. wanted PUT", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Update(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", runtime.ContentTypeJSON)
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Update(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Update(tc.obj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when updating %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.obj) {
|
||||
t.Errorf("Update(%q) want: %v\ngot: %v", tc.name, tc.obj, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
name string
|
||||
namespace string
|
||||
events []watch.Event
|
||||
path string
|
||||
query string
|
||||
}{
|
||||
{
|
||||
name: "normal_watch",
|
||||
path: "/apis/gtest/vtest/rtest",
|
||||
query: "watch=true",
|
||||
events: []watch.Event{
|
||||
{Type: watch.Added, Object: getObject("gtest/vTest", "rTest", "normal_watch")},
|
||||
{Type: watch.Modified, Object: getObject("gtest/vTest", "rTest", "normal_watch")},
|
||||
{Type: watch.Deleted, Object: getObject("gtest/vTest", "rTest", "normal_watch")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "namespaced_watch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
query: "watch=true",
|
||||
events: []watch.Event{
|
||||
{Type: watch.Added, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")},
|
||||
{Type: watch.Modified, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")},
|
||||
{Type: watch.Deleted, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Watch(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Watch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
if r.URL.RawQuery != tc.query {
|
||||
t.Errorf("Watch(%q) got query %s. wanted %s", tc.name, r.URL.RawQuery, tc.query)
|
||||
}
|
||||
|
||||
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, dynamicCodec{}), dynamicCodec{})
|
||||
for _, e := range tc.events {
|
||||
enc.Encode(&e)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
watcher, err := cl.Resource(resource, tc.namespace).Watch(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when watching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, want := range tc.events {
|
||||
got := <-watcher.ResultChan()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("Watch(%q) want: %v\ngot: %v", tc.name, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
patch []byte
|
||||
want *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "normal_patch",
|
||||
path: "/apis/gtest/vtest/rtest/normal_patch",
|
||||
patch: getJSON("gtest/vTest", "rTest", "normal_patch"),
|
||||
want: getObject("gtest/vTest", "rTest", "normal_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
name: "namespaced_patch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_patch",
|
||||
patch: getJSON("gtest/vTest", "rTest", "namespaced_patch"),
|
||||
want: getObject("gtest/vTest", "rTest", "namespaced_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_patch",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "namespaced_subresource_patch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PATCH" {
|
||||
t.Errorf("Patch(%q) got HTTP method %s. wanted PATCH", tc.name, r.Method)
|
||||
}
|
||||
|
||||
if r.URL.Path != tc.path {
|
||||
t.Errorf("Patch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path)
|
||||
}
|
||||
|
||||
content := r.Header.Get("Content-Type")
|
||||
if content != string(types.StrategicMergePatchType) {
|
||||
t.Errorf("Patch(%q) got Content-Type %s. wanted %s", tc.name, content, types.StrategicMergePatchType)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Errorf("Patch(%q) unexpected error reading body: %v", tc.name, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(data)
|
||||
})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating client: %v", err)
|
||||
continue
|
||||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Patch(tc.name, types.StrategicMergePatchType, tc.patch)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when patching %q: %v", tc.name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(got, tc.want) {
|
||||
t.Errorf("Patch(%q) want: %v\ngot: %v", tc.name, tc.want, got)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,7 @@ load(
|
|||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"client_test.go",
|
||||
"dynamic_util_test.go",
|
||||
],
|
||||
srcs = ["client_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
|
@ -29,10 +26,7 @@ go_test(
|
|||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"bad_debt.go",
|
||||
"client.go",
|
||||
"client_pool.go",
|
||||
"dynamic_util.go",
|
||||
"interface.go",
|
||||
"scheme.go",
|
||||
"simple.go",
|
||||
],
|
||||
|
@ -49,7 +43,6 @@ go_library(
|
|||
"//vendor/k8s.io/apimachinery/pkg/runtime/serializer/versioning:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/kubernetes/scheme:go_default_library",
|
||||
"//vendor/k8s.io/client-go/rest:go_default_library",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -58,12 +58,11 @@ func getObject(version, kind, name string) *unstructured.Unstructured {
|
|||
}
|
||||
}
|
||||
|
||||
func getClientServer(gv *schema.GroupVersion, h func(http.ResponseWriter, *http.Request)) (Interface, *httptest.Server, error) {
|
||||
func getClientServer(h func(http.ResponseWriter, *http.Request)) (Interface, *httptest.Server, error) {
|
||||
srv := httptest.NewServer(http.HandlerFunc(h))
|
||||
cl, err := NewClient(&restclient.Config{
|
||||
Host: srv.URL,
|
||||
ContentConfig: restclient.ContentConfig{GroupVersion: gv},
|
||||
}, *gv)
|
||||
cl, err := NewForConfig(&restclient.Config{
|
||||
Host: srv.URL,
|
||||
})
|
||||
if err != nil {
|
||||
srv.Close()
|
||||
return nil, nil, err
|
||||
|
@ -116,9 +115,8 @@ func TestList(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: "rtest"}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("List(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
@ -136,7 +134,7 @@ func TestList(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).List(metav1.ListOptions{})
|
||||
got, err := cl.Resource(resource).Namespace(tc.namespace).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when listing %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -150,12 +148,13 @@ func TestList(t *testing.T) {
|
|||
|
||||
func TestGet(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.Unstructured
|
||||
resource string
|
||||
subresource []string
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
resp []byte
|
||||
want *unstructured.Unstructured
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
|
@ -173,25 +172,26 @@ func TestGet(t *testing.T) {
|
|||
want: getObject("vTest", "rTest", "namespaced_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_get",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "normal_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "normal_subresource_get"),
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
name: "normal_subresource_get",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "normal_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "normal_subresource_get"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
namespace: "nstest",
|
||||
name: "namespaced_subresource_get",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "namespaced_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "namespaced_subresource_get"),
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
namespace: "nstest",
|
||||
name: "namespaced_subresource_get",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_get/srtest",
|
||||
resp: getJSON("vTest", "srTest", "namespaced_subresource_get"),
|
||||
want: getObject("vTest", "srTest", "namespaced_subresource_get"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: tc.resource}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Get(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ func TestGet(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Get(tc.name, metav1.GetOptions{})
|
||||
got, err := cl.Resource(resource).Namespace(tc.namespace).Get(tc.name, metav1.GetOptions{}, tc.subresource...)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when getting %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -230,6 +230,7 @@ func TestDelete(t *testing.T) {
|
|||
Status: metav1.StatusSuccess,
|
||||
}
|
||||
tcs := []struct {
|
||||
subresource []string
|
||||
namespace string
|
||||
name string
|
||||
path string
|
||||
|
@ -244,6 +245,17 @@ func TestDelete(t *testing.T) {
|
|||
name: "namespaced_delete",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete",
|
||||
},
|
||||
{
|
||||
subresource: []string{"srtest"},
|
||||
name: "normal_delete",
|
||||
path: "/apis/gtest/vtest/rtest/normal_delete/srtest",
|
||||
},
|
||||
{
|
||||
subresource: []string{"srtest"},
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete/srtest",
|
||||
},
|
||||
{
|
||||
namespace: "nstest",
|
||||
name: "namespaced_delete_with_options",
|
||||
|
@ -252,9 +264,8 @@ func TestDelete(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: "rtest"}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("Delete(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
@ -272,7 +283,7 @@ func TestDelete(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).Delete(tc.name, tc.deleteOptions)
|
||||
err = cl.Resource(resource).Namespace(tc.namespace).Delete(tc.name, tc.deleteOptions, tc.subresource...)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -301,9 +312,8 @@ func TestDeleteCollection(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: "rtest"}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "DELETE" {
|
||||
t.Errorf("DeleteCollection(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method)
|
||||
}
|
||||
|
@ -321,7 +331,7 @@ func TestDeleteCollection(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
err = cl.Resource(resource, tc.namespace).DeleteCollection(nil, metav1.ListOptions{})
|
||||
err = cl.Resource(resource).Namespace(tc.namespace).DeleteCollection(nil, metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when deleting collection %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -331,11 +341,12 @@ func TestDeleteCollection(t *testing.T) {
|
|||
|
||||
func TestCreate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
resource string
|
||||
subresource []string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
|
@ -350,11 +361,25 @@ func TestCreate(t *testing.T) {
|
|||
path: "/apis/gtest/vtest/namespaces/nstest/rtest",
|
||||
obj: getObject("gtest/vTest", "rTest", "namespaced_create"),
|
||||
},
|
||||
{
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
name: "normal_subresource_create",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_create/srtest",
|
||||
obj: getObject("vTest", "srTest", "normal_subresource_create"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/",
|
||||
subresource: []string{"srtest"},
|
||||
name: "namespaced_subresource_create",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_create/srtest",
|
||||
obj: getObject("vTest", "srTest", "namespaced_subresource_create"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: tc.resource}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "POST" {
|
||||
t.Errorf("Create(%q) got HTTP method %s. wanted POST", tc.name, r.Method)
|
||||
}
|
||||
|
@ -379,7 +404,7 @@ func TestCreate(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Create(tc.obj)
|
||||
got, err := cl.Resource(resource).Namespace(tc.namespace).Create(tc.obj, tc.subresource...)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -393,11 +418,12 @@ func TestCreate(t *testing.T) {
|
|||
|
||||
func TestUpdate(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
resource string
|
||||
subresource []string
|
||||
name string
|
||||
namespace string
|
||||
obj *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
|
@ -413,23 +439,24 @@ func TestUpdate(t *testing.T) {
|
|||
obj: getObject("gtest/vTest", "rTest", "namespaced_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_update",
|
||||
path: "/apis/gtest/vtest/rtest/normal_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "normal_update"),
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
name: "normal_subresource_update",
|
||||
path: "/apis/gtest/vtest/rtest/normal_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "normal_update"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "namespaced_subresource_update",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "namespaced_update"),
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
name: "namespaced_subresource_update",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update/srtest",
|
||||
obj: getObject("gtest/vTest", "srTest", "namespaced_update"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: tc.resource}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PUT" {
|
||||
t.Errorf("Update(%q) got HTTP method %s. wanted PUT", tc.name, r.Method)
|
||||
}
|
||||
|
@ -454,7 +481,7 @@ func TestUpdate(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Update(tc.obj)
|
||||
got, err := cl.Resource(resource).Namespace(tc.namespace).Update(tc.obj, tc.subresource...)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when updating %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -497,9 +524,8 @@ func TestWatch(t *testing.T) {
|
|||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: "rtest"}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "GET" {
|
||||
t.Errorf("Watch(%q) got HTTP method %s. wanted GET", tc.name, r.Method)
|
||||
}
|
||||
|
@ -511,7 +537,7 @@ func TestWatch(t *testing.T) {
|
|||
t.Errorf("Watch(%q) got query %s. wanted %s", tc.name, r.URL.RawQuery, tc.query)
|
||||
}
|
||||
|
||||
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, dynamicCodec{}), dynamicCodec{})
|
||||
enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, unstructured.UnstructuredJSONScheme), unstructured.UnstructuredJSONScheme)
|
||||
for _, e := range tc.events {
|
||||
enc.Encode(&e)
|
||||
}
|
||||
|
@ -522,7 +548,7 @@ func TestWatch(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
watcher, err := cl.Resource(resource, tc.namespace).Watch(metav1.ListOptions{})
|
||||
watcher, err := cl.Resource(resource).Namespace(tc.namespace).Watch(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when watching %q: %v", tc.name, err)
|
||||
continue
|
||||
|
@ -539,12 +565,13 @@ func TestWatch(t *testing.T) {
|
|||
|
||||
func TestPatch(t *testing.T) {
|
||||
tcs := []struct {
|
||||
resource string
|
||||
name string
|
||||
namespace string
|
||||
patch []byte
|
||||
want *unstructured.Unstructured
|
||||
path string
|
||||
resource string
|
||||
subresource []string
|
||||
name string
|
||||
namespace string
|
||||
patch []byte
|
||||
want *unstructured.Unstructured
|
||||
path string
|
||||
}{
|
||||
{
|
||||
resource: "rtest",
|
||||
|
@ -562,25 +589,26 @@ func TestPatch(t *testing.T) {
|
|||
want: getObject("gtest/vTest", "rTest", "namespaced_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "normal_subresource_patch",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
name: "normal_subresource_patch",
|
||||
path: "/apis/gtest/vtest/rtest/normal_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "normal_subresource_patch"),
|
||||
},
|
||||
{
|
||||
resource: "rtest/srtest",
|
||||
name: "namespaced_subresource_patch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
resource: "rtest",
|
||||
subresource: []string{"srtest"},
|
||||
name: "namespaced_subresource_patch",
|
||||
namespace: "nstest",
|
||||
path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_patch/srtest",
|
||||
patch: getJSON("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
want: getObject("gtest/vTest", "srTest", "namespaced_subresource_patch"),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"}
|
||||
resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0}
|
||||
cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) {
|
||||
resource := schema.GroupVersionResource{Group: "gtest", Version: "vtest", Resource: tc.resource}
|
||||
cl, srv, err := getClientServer(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != "PATCH" {
|
||||
t.Errorf("Patch(%q) got HTTP method %s. wanted PATCH", tc.name, r.Method)
|
||||
}
|
||||
|
@ -610,7 +638,7 @@ func TestPatch(t *testing.T) {
|
|||
}
|
||||
defer srv.Close()
|
||||
|
||||
got, err := cl.Resource(resource, tc.namespace).Patch(tc.name, types.StrategicMergePatchType, tc.patch)
|
||||
got, err := cl.Resource(resource).Namespace(tc.namespace).Patch(tc.name, types.StrategicMergePatchType, tc.patch, tc.subresource...)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when patching %q: %v", tc.name, err)
|
||||
continue
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
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 dynamic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
// NewDiscoveryRESTMapper returns a RESTMapper based on discovery information.
|
||||
func NewDiscoveryRESTMapper(resources []*metav1.APIResourceList) (*meta.DefaultRESTMapper, error) {
|
||||
rm := meta.NewDefaultRESTMapper(nil)
|
||||
for _, resourceList := range resources {
|
||||
gv, err := schema.ParseGroupVersion(resourceList.GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, resource := range resourceList.APIResources {
|
||||
gvk := gv.WithKind(resource.Kind)
|
||||
scope := meta.RESTScopeRoot
|
||||
if resource.Namespaced {
|
||||
scope = meta.RESTScopeNamespace
|
||||
}
|
||||
rm.Add(gvk, scope)
|
||||
}
|
||||
}
|
||||
return rm, nil
|
||||
}
|
||||
|
||||
// ObjectTyper provides an ObjectTyper implementation for
|
||||
// unstructured.Unstructured object based on discovery information.
|
||||
type ObjectTyper struct {
|
||||
registered map[schema.GroupVersionKind]bool
|
||||
}
|
||||
|
||||
// NewObjectTyper constructs an ObjectTyper from discovery information.
|
||||
func NewObjectTyper(resources []*metav1.APIResourceList) (runtime.ObjectTyper, error) {
|
||||
ot := &ObjectTyper{registered: make(map[schema.GroupVersionKind]bool)}
|
||||
for _, resourceList := range resources {
|
||||
gv, err := schema.ParseGroupVersion(resourceList.GroupVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, resource := range resourceList.APIResources {
|
||||
ot.registered[gv.WithKind(resource.Kind)] = true
|
||||
}
|
||||
}
|
||||
return ot, 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 *unstructured.Unstructured or has no group,version,kind
|
||||
// information.
|
||||
func (ot *ObjectTyper) ObjectKinds(obj runtime.Object) ([]schema.GroupVersionKind, bool, error) {
|
||||
if _, ok := obj.(*unstructured.Unstructured); !ok {
|
||||
return nil, false, fmt.Errorf("type %T is invalid for determining dynamic object types", obj)
|
||||
}
|
||||
return []schema.GroupVersionKind{obj.GetObjectKind().GroupVersionKind()}, false, nil
|
||||
}
|
||||
|
||||
// Recognizes returns true if the provided group,version,kind was in
|
||||
// the discovery information.
|
||||
func (ot *ObjectTyper) Recognizes(gvk schema.GroupVersionKind) bool {
|
||||
return ot.registered[gvk]
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
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 dynamic
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestDiscoveryRESTMapper(t *testing.T) {
|
||||
resources := []*metav1.APIResourceList{
|
||||
{
|
||||
GroupVersion: "test/beta1",
|
||||
APIResources: []metav1.APIResource{
|
||||
{
|
||||
Name: "test_kinds",
|
||||
Namespaced: true,
|
||||
Kind: "test_kind",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
gvk := schema.GroupVersionKind{
|
||||
Group: "test",
|
||||
Version: "beta1",
|
||||
Kind: "test_kind",
|
||||
}
|
||||
|
||||
mapper, err := NewDiscoveryRESTMapper(resources)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating mapper: %s", err)
|
||||
}
|
||||
|
||||
for _, res := range []schema.GroupVersionResource{
|
||||
{
|
||||
Group: "test",
|
||||
Version: "beta1",
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
{
|
||||
Version: "beta1",
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
{
|
||||
Group: "test",
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
{
|
||||
Resource: "test_kinds",
|
||||
},
|
||||
} {
|
||||
got, err := mapper.KindFor(res)
|
||||
if err != nil {
|
||||
t.Errorf("KindFor(%#v) unexpected error: %s", res, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if got != gvk {
|
||||
t.Errorf("KindFor(%#v) = %#v; want %#v", res, got, gvk)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,11 +7,7 @@ load(
|
|||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"client.go",
|
||||
"client_pool.go",
|
||||
"simple.go",
|
||||
],
|
||||
srcs = ["simple.go"],
|
||||
importpath = "k8s.io/client-go/dynamic/fake",
|
||||
deps = [
|
||||
"//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library",
|
||||
|
@ -25,7 +21,6 @@ go_library(
|
|||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||
"//vendor/k8s.io/client-go/testing:go_default_library",
|
||||
"//vendor/k8s.io/client-go/util/flowcontrol:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -1,163 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 fake provides a fake client interface to arbitrary Kubernetes
|
||||
// APIs that exposes common high level operations and exposes common
|
||||
// metadata.
|
||||
package fake
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/testing"
|
||||
"k8s.io/client-go/util/flowcontrol"
|
||||
)
|
||||
|
||||
// FakeClient is a fake implementation of dynamic.Interface.
|
||||
type FakeClient struct {
|
||||
GroupVersion schema.GroupVersion
|
||||
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
// GetRateLimiter returns the rate limiter for this client.
|
||||
func (c *FakeClient) GetRateLimiter() flowcontrol.RateLimiter {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Resource returns an API interface to the specified resource for this client's
|
||||
// group and version. If resource is not a namespaced resource, then namespace
|
||||
// is ignored. The ResourceClient inherits the parameter codec of this client
|
||||
func (c *FakeClient) Resource(resource *metav1.APIResource, namespace string) dynamic.ResourceInterface {
|
||||
return &FakeResourceClient{
|
||||
Resource: c.GroupVersion.WithResource(resource.Name),
|
||||
Kind: c.GroupVersion.WithKind(resource.Kind),
|
||||
Namespace: namespace,
|
||||
|
||||
Fake: c.Fake,
|
||||
}
|
||||
}
|
||||
|
||||
// ParameterCodec returns a client with the provided parameter codec.
|
||||
func (c *FakeClient) ParameterCodec(parameterCodec runtime.ParameterCodec) dynamic.Interface {
|
||||
return &FakeClient{
|
||||
Fake: c.Fake,
|
||||
}
|
||||
}
|
||||
|
||||
// FakeResourceClient is a fake implementation of dynamic.ResourceInterface
|
||||
type FakeResourceClient struct {
|
||||
Resource schema.GroupVersionResource
|
||||
Kind schema.GroupVersionKind
|
||||
Namespace string
|
||||
|
||||
*testing.Fake
|
||||
}
|
||||
|
||||
// List returns a list of objects for this resource.
|
||||
func (c *FakeResourceClient) List(opts metav1.ListOptions) (runtime.Object, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewListAction(c.Resource, c.Kind, c.Namespace, opts), &unstructured.UnstructuredList{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
label, _, _ := testing.ExtractFromListOptions(opts)
|
||||
if label == nil {
|
||||
label = labels.Everything()
|
||||
}
|
||||
list := &unstructured.UnstructuredList{}
|
||||
for _, item := range obj.(*unstructured.UnstructuredList).Items {
|
||||
if label.Matches(labels.Set(item.GetLabels())) {
|
||||
list.Items = append(list.Items, item)
|
||||
}
|
||||
}
|
||||
return list, err
|
||||
}
|
||||
|
||||
// Get gets the resource with the specified name.
|
||||
func (c *FakeResourceClient) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewGetAction(c.Resource, c.Namespace, name), &unstructured.Unstructured{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return obj.(*unstructured.Unstructured), err
|
||||
}
|
||||
|
||||
// Delete deletes the resource with the specified name.
|
||||
func (c *FakeResourceClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteAction(c.Resource, c.Namespace, name), &unstructured.Unstructured{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCollection deletes a collection of objects.
|
||||
func (c *FakeResourceClient) DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||
_, err := c.Fake.
|
||||
Invokes(testing.NewDeleteCollectionAction(c.Resource, c.Namespace, listOptions), &unstructured.Unstructured{})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Create creates the provided resource.
|
||||
func (c *FakeResourceClient) Create(inObj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewCreateAction(c.Resource, c.Namespace, inObj), &unstructured.Unstructured{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*unstructured.Unstructured), err
|
||||
}
|
||||
|
||||
// Update updates the provided resource.
|
||||
func (c *FakeResourceClient) Update(inObj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewUpdateAction(c.Resource, c.Namespace, inObj), &unstructured.Unstructured{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*unstructured.Unstructured), err
|
||||
}
|
||||
|
||||
// Watch returns a watch.Interface that watches the resource.
|
||||
func (c *FakeResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return c.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(c.Resource, c.Namespace, opts))
|
||||
}
|
||||
|
||||
// Patch patches the provided resource.
|
||||
func (c *FakeResourceClient) Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) {
|
||||
obj, err := c.Fake.
|
||||
Invokes(testing.NewPatchAction(c.Resource, c.Namespace, name, data), &unstructured.Unstructured{})
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
}
|
||||
return obj.(*unstructured.Unstructured), err
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 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 fake provides a fake client interface to arbitrary Kubernetes
|
||||
// APIs that exposes common high level operations and exposes common
|
||||
// metadata.
|
||||
package fake
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/testing"
|
||||
)
|
||||
|
||||
// FakeClientPool provides a fake implementation of dynamic.ClientPool.
|
||||
// It assumes resource GroupVersions are the same as their corresponding kind GroupVersions.
|
||||
type FakeClientPool struct {
|
||||
testing.Fake
|
||||
}
|
||||
|
||||
// ClientForGroupVersionKind returns a client configured for the specified groupVersionResource.
|
||||
// Resource may be empty.
|
||||
func (p *FakeClientPool) ClientForGroupVersionResource(resource schema.GroupVersionResource) (dynamic.Interface, error) {
|
||||
return p.ClientForGroupVersionKind(resource.GroupVersion().WithKind(""))
|
||||
}
|
||||
|
||||
// ClientForGroupVersionKind returns a client configured for the specified groupVersionKind.
|
||||
// Kind may be empty.
|
||||
func (p *FakeClientPool) ClientForGroupVersionKind(kind schema.GroupVersionKind) (dynamic.Interface, error) {
|
||||
// we can just create a new client every time for testing purposes
|
||||
return &FakeClient{
|
||||
GroupVersion: kind.GroupVersion(),
|
||||
Fake: &p.Fake,
|
||||
}, nil
|
||||
}
|
|
@ -17,6 +17,8 @@ limitations under the License.
|
|||
package fake
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -63,37 +65,54 @@ type FakeDynamicClient struct {
|
|||
}
|
||||
|
||||
type dynamicResourceClient struct {
|
||||
client *FakeDynamicClient
|
||||
namespace string
|
||||
resource schema.GroupVersionResource
|
||||
subresource string
|
||||
client *FakeDynamicClient
|
||||
namespace string
|
||||
resource schema.GroupVersionResource
|
||||
}
|
||||
|
||||
var _ dynamic.DynamicInterface = &FakeDynamicClient{}
|
||||
var _ dynamic.Interface = &FakeDynamicClient{}
|
||||
|
||||
func (c *FakeDynamicClient) Resource(resource schema.GroupVersionResource) dynamic.NamespaceableDynamicResourceInterface {
|
||||
func (c *FakeDynamicClient) Resource(resource schema.GroupVersionResource) dynamic.NamespaceableResourceInterface {
|
||||
return &dynamicResourceClient{client: c, resource: resource}
|
||||
}
|
||||
|
||||
// Deprecated, this isn't how we want to do it
|
||||
func (c *FakeDynamicClient) ClusterSubresource(resource schema.GroupVersionResource, subresource string) dynamic.DynamicResourceInterface {
|
||||
return &dynamicResourceClient{client: c, resource: resource, subresource: subresource}
|
||||
}
|
||||
|
||||
// Deprecated, this isn't how we want to do it
|
||||
func (c *FakeDynamicClient) NamespacedSubresource(resource schema.GroupVersionResource, subresource, namespace string) dynamic.DynamicResourceInterface {
|
||||
return &dynamicResourceClient{client: c, resource: resource, namespace: namespace, subresource: subresource}
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Namespace(ns string) dynamic.DynamicResourceInterface {
|
||||
func (c *dynamicResourceClient) Namespace(ns string) dynamic.ResourceInterface {
|
||||
ret := *c
|
||||
ret.namespace = ns
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
uncastRet, err := c.client.Fake.
|
||||
Invokes(testing.NewCreateAction(c.resource, c.namespace, obj), obj)
|
||||
func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
var uncastRet runtime.Object
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootCreateAction(c.resource, obj), obj)
|
||||
|
||||
case len(c.namespace) == 0 && len(subresources) > 0:
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := accessor.GetName()
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), obj), obj)
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewCreateAction(c.resource, c.namespace, obj), obj)
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) > 0:
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := accessor.GetName()
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewCreateSubresourceAction(c.resource, name, strings.Join(subresources, "/"), c.namespace, obj), obj)
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -109,9 +128,27 @@ func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured) (*unstruc
|
|||
return ret, err
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
uncastRet, err := c.client.Fake.
|
||||
Invokes(testing.NewUpdateAction(c.resource, c.namespace, obj), obj)
|
||||
func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
var uncastRet runtime.Object
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootUpdateAction(c.resource, obj), obj)
|
||||
|
||||
case len(c.namespace) == 0 && len(subresources) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), obj), obj)
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewUpdateAction(c.resource, c.namespace, obj), obj)
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, obj), obj)
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -128,8 +165,18 @@ func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured) (*unstruc
|
|||
}
|
||||
|
||||
func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
uncastRet, err := c.client.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(c.resource, "status", c.namespace, obj), obj)
|
||||
var uncastRet runtime.Object
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootUpdateSubresourceAction(c.resource, "status", obj), obj)
|
||||
|
||||
case len(c.namespace) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewUpdateSubresourceAction(c.resource, "status", c.namespace, obj), obj)
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -145,23 +192,65 @@ func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*u
|
|||
return ret, err
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
_, err := c.client.Fake.
|
||||
Invokes(testing.NewDeleteAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})
|
||||
func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0 && len(subresources) == 0:
|
||||
_, err = c.client.Fake.
|
||||
Invokes(testing.NewRootDeleteAction(c.resource, name), &metav1.Status{Status: "dynamic delete fail"})
|
||||
|
||||
case len(c.namespace) == 0 && len(subresources) > 0:
|
||||
_, err = c.client.Fake.
|
||||
Invokes(testing.NewRootDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic delete fail"})
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) == 0:
|
||||
_, err = c.client.Fake.
|
||||
Invokes(testing.NewDeleteAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) > 0:
|
||||
_, err = c.client.Fake.
|
||||
Invokes(testing.NewDeleteSubresourceAction(c.resource, strings.Join(subresources, "/"), c.namespace, name), &metav1.Status{Status: "dynamic delete fail"})
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||
action := testing.NewDeleteCollectionAction(c.resource, c.namespace, listOptions)
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0:
|
||||
action := testing.NewRootDeleteCollectionAction(c.resource, listOptions)
|
||||
_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})
|
||||
|
||||
case len(c.namespace) > 0:
|
||||
action := testing.NewDeleteCollectionAction(c.resource, c.namespace, listOptions)
|
||||
_, err = c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})
|
||||
|
||||
}
|
||||
|
||||
_, err := c.client.Fake.Invokes(action, &metav1.Status{Status: "dynamic deletecollection fail"})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
|
||||
uncastRet, err := c.client.Fake.
|
||||
Invokes(testing.NewGetAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic get fail"})
|
||||
func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
var uncastRet runtime.Object
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootGetAction(c.resource, name), &metav1.Status{Status: "dynamic get fail"})
|
||||
|
||||
case len(c.namespace) == 0 && len(subresources) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootGetSubresourceAction(c.resource, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"})
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewGetAction(c.resource, c.namespace, name), &metav1.Status{Status: "dynamic get fail"})
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewGetSubresourceAction(c.resource, c.namespace, strings.Join(subresources, "/"), name), &metav1.Status{Status: "dynamic get fail"})
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -178,8 +267,18 @@ func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstr
|
|||
}
|
||||
|
||||
func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
|
||||
obj, err := c.client.Fake.
|
||||
Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Version: "v1", Kind: "List"}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"})
|
||||
var obj runtime.Object
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0:
|
||||
obj, err = c.client.Fake.
|
||||
Invokes(testing.NewRootListAction(c.resource, schema.GroupVersionKind{Version: "v1", Kind: "List"}, opts), &metav1.Status{Status: "dynamic list fail"})
|
||||
|
||||
case len(c.namespace) > 0:
|
||||
obj, err = c.client.Fake.
|
||||
Invokes(testing.NewListAction(c.resource, schema.GroupVersionKind{Version: "v1", Kind: "List"}, c.namespace, opts), &metav1.Status{Status: "dynamic list fail"})
|
||||
|
||||
}
|
||||
|
||||
if obj == nil {
|
||||
return nil, err
|
||||
|
@ -213,13 +312,41 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
|
|||
}
|
||||
|
||||
func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
return c.client.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(c.resource, c.namespace, opts))
|
||||
switch {
|
||||
case len(c.namespace) == 0:
|
||||
return c.client.Fake.
|
||||
InvokesWatch(testing.NewRootWatchAction(c.resource, opts))
|
||||
|
||||
case len(c.namespace) > 0:
|
||||
return c.client.Fake.
|
||||
InvokesWatch(testing.NewWatchAction(c.resource, c.namespace, opts))
|
||||
|
||||
}
|
||||
|
||||
panic("math broke")
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
uncastRet, err := c.client.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(c.resource, c.namespace, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})
|
||||
var uncastRet runtime.Object
|
||||
var err error
|
||||
switch {
|
||||
case len(c.namespace) == 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootPatchAction(c.resource, name, data), &metav1.Status{Status: "dynamic patch fail"})
|
||||
|
||||
case len(c.namespace) == 0 && len(subresources) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewRootPatchSubresourceAction(c.resource, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) == 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewPatchAction(c.resource, c.namespace, name, data), &metav1.Status{Status: "dynamic patch fail"})
|
||||
|
||||
case len(c.namespace) > 0 && len(subresources) > 0:
|
||||
uncastRet, err = c.client.Fake.
|
||||
Invokes(testing.NewPatchSubresourceAction(c.resource, c.namespace, name, data, subresources...), &metav1.Status{Status: "dynamic patch fail"})
|
||||
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
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 dynamic
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface
|
||||
}
|
||||
|
||||
type ResourceInterface interface {
|
||||
Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error)
|
||||
Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error)
|
||||
UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
Delete(name string, options *metav1.DeleteOptions, subresources ...string) error
|
||||
DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error
|
||||
Get(name string, options metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error)
|
||||
List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type NamespaceableResourceInterface interface {
|
||||
Namespace(string) ResourceInterface
|
||||
ResourceInterface
|
||||
}
|
||||
|
||||
// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is optional.
|
||||
// TODO find a better place to move this for existing callers
|
||||
type APIPathResolverFunc func(kind schema.GroupVersionKind) string
|
||||
|
||||
// LegacyAPIPathResolverFunc can resolve paths properly with the legacy API.
|
||||
// TODO find a better place to move this for existing callers
|
||||
func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string {
|
||||
if len(kind.Group) == 0 {
|
||||
return "/api"
|
||||
}
|
||||
return "/apis"
|
||||
}
|
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
package dynamic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
|
@ -31,39 +30,13 @@ import (
|
|||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
type DynamicInterface interface {
|
||||
Resource(resource schema.GroupVersionResource) NamespaceableDynamicResourceInterface
|
||||
|
||||
// Deprecated, this isn't how we want to do it
|
||||
ClusterSubresource(resource schema.GroupVersionResource, subresource string) DynamicResourceInterface
|
||||
// Deprecated, this isn't how we want to do it
|
||||
NamespacedSubresource(resource schema.GroupVersionResource, subresource, namespace string) DynamicResourceInterface
|
||||
}
|
||||
|
||||
type DynamicResourceInterface interface {
|
||||
Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
UpdateStatus(obj *unstructured.Unstructured) (*unstructured.Unstructured, error)
|
||||
Delete(name string, options *metav1.DeleteOptions) error
|
||||
DeleteCollection(options *metav1.DeleteOptions, listOptions metav1.ListOptions) error
|
||||
Get(name string, options metav1.GetOptions) (*unstructured.Unstructured, error)
|
||||
List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error)
|
||||
Watch(opts metav1.ListOptions) (watch.Interface, error)
|
||||
Patch(name string, pt types.PatchType, data []byte, subresources ...string) (*unstructured.Unstructured, error)
|
||||
}
|
||||
|
||||
type NamespaceableDynamicResourceInterface interface {
|
||||
Namespace(string) DynamicResourceInterface
|
||||
DynamicResourceInterface
|
||||
}
|
||||
|
||||
type dynamicClient struct {
|
||||
client *rest.RESTClient
|
||||
}
|
||||
|
||||
var _ DynamicInterface = &dynamicClient{}
|
||||
var _ Interface = &dynamicClient{}
|
||||
|
||||
func NewForConfig(inConfig *rest.Config) (DynamicInterface, error) {
|
||||
func NewForConfig(inConfig *rest.Config) (Interface, error) {
|
||||
config := rest.CopyConfig(inConfig)
|
||||
// for serializing the options
|
||||
config.GroupVersion = &schema.GroupVersion{}
|
||||
|
@ -84,40 +57,36 @@ func NewForConfig(inConfig *rest.Config) (DynamicInterface, error) {
|
|||
}
|
||||
|
||||
type dynamicResourceClient struct {
|
||||
client *dynamicClient
|
||||
namespace string
|
||||
resource schema.GroupVersionResource
|
||||
subresource string
|
||||
client *dynamicClient
|
||||
namespace string
|
||||
resource schema.GroupVersionResource
|
||||
}
|
||||
|
||||
func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableDynamicResourceInterface {
|
||||
func (c *dynamicClient) Resource(resource schema.GroupVersionResource) NamespaceableResourceInterface {
|
||||
return &dynamicResourceClient{client: c, resource: resource}
|
||||
}
|
||||
|
||||
func (c *dynamicClient) ClusterSubresource(resource schema.GroupVersionResource, subresource string) DynamicResourceInterface {
|
||||
return &dynamicResourceClient{client: c, resource: resource, subresource: subresource}
|
||||
}
|
||||
func (c *dynamicClient) NamespacedSubresource(resource schema.GroupVersionResource, subresource, namespace string) DynamicResourceInterface {
|
||||
return &dynamicResourceClient{client: c, resource: resource, namespace: namespace, subresource: subresource}
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Namespace(ns string) DynamicResourceInterface {
|
||||
func (c *dynamicResourceClient) Namespace(ns string) ResourceInterface {
|
||||
ret := *c
|
||||
ret.namespace = ns
|
||||
return &ret
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
if len(c.subresource) > 0 {
|
||||
return nil, fmt.Errorf("create not supported for subresources")
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := ""
|
||||
if len(subresources) > 0 {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name = accessor.GetName()
|
||||
}
|
||||
|
||||
result := c.client.client.Post().AbsPath(c.makeURLSegments("")...).Body(outBytes).Do()
|
||||
result := c.client.client.Post().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(outBytes).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -133,7 +102,7 @@ func (c *dynamicResourceClient) Create(obj *unstructured.Unstructured) (*unstruc
|
|||
return uncastObj.(*unstructured.Unstructured), nil
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) {
|
||||
func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -143,7 +112,7 @@ func (c *dynamicResourceClient) Update(obj *unstructured.Unstructured) (*unstruc
|
|||
return nil, err
|
||||
}
|
||||
|
||||
result := c.client.client.Put().AbsPath(c.makeURLSegments(accessor.GetName())...).Body(outBytes).Do()
|
||||
result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), subresources...)...).Body(outBytes).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -171,6 +140,10 @@ func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*u
|
|||
}
|
||||
|
||||
result := c.client.client.Put().AbsPath(append(c.makeURLSegments(accessor.GetName()), "status")...).Body(outBytes).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
retBytes, err := result.Raw()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -182,7 +155,7 @@ func (c *dynamicResourceClient) UpdateStatus(obj *unstructured.Unstructured) (*u
|
|||
return uncastObj.(*unstructured.Unstructured), nil
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions) error {
|
||||
func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions, subresources ...string) error {
|
||||
if opts == nil {
|
||||
opts = &metav1.DeleteOptions{}
|
||||
}
|
||||
|
@ -191,15 +164,11 @@ func (c *dynamicResourceClient) Delete(name string, opts *metav1.DeleteOptions)
|
|||
return err
|
||||
}
|
||||
|
||||
result := c.client.client.Delete().AbsPath(c.makeURLSegments(name)...).Body(deleteOptionsByte).Do()
|
||||
result := c.client.client.Delete().AbsPath(append(c.makeURLSegments(name), subresources...)...).Body(deleteOptionsByte).Do()
|
||||
return result.Error()
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, listOptions metav1.ListOptions) error {
|
||||
if len(c.subresource) > 0 {
|
||||
return fmt.Errorf("deletecollection not supported for subresources")
|
||||
}
|
||||
|
||||
if opts == nil {
|
||||
opts = &metav1.DeleteOptions{}
|
||||
}
|
||||
|
@ -212,8 +181,8 @@ func (c *dynamicResourceClient) DeleteCollection(opts *metav1.DeleteOptions, lis
|
|||
return result.Error()
|
||||
}
|
||||
|
||||
func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) {
|
||||
result := c.client.client.Get().AbsPath(c.makeURLSegments(name)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
|
||||
func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions, subresources ...string) (*unstructured.Unstructured, error) {
|
||||
result := c.client.client.Get().AbsPath(append(c.makeURLSegments(name), subresources...)...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -229,10 +198,6 @@ func (c *dynamicResourceClient) Get(name string, opts metav1.GetOptions) (*unstr
|
|||
}
|
||||
|
||||
func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.UnstructuredList, error) {
|
||||
if len(c.subresource) > 0 {
|
||||
return nil, fmt.Errorf("list not supported for subresources")
|
||||
}
|
||||
|
||||
result := c.client.client.Get().AbsPath(c.makeURLSegments("")...).SpecificallyVersionedParams(&opts, dynamicParameterCodec, versionV1).Do()
|
||||
if err := result.Error(); err != nil {
|
||||
return nil, err
|
||||
|
@ -257,10 +222,6 @@ func (c *dynamicResourceClient) List(opts metav1.ListOptions) (*unstructured.Uns
|
|||
}
|
||||
|
||||
func (c *dynamicResourceClient) Watch(opts metav1.ListOptions) (watch.Interface, error) {
|
||||
if len(c.subresource) > 0 {
|
||||
return nil, fmt.Errorf("watch not supported for subresources")
|
||||
}
|
||||
|
||||
internalGV := schema.GroupVersions{
|
||||
{Group: c.resource.Group, Version: runtime.APIVersionInternal},
|
||||
// always include the legacy group as a decoding target to handle non-error `Status` return types
|
||||
|
@ -320,15 +281,6 @@ func (c *dynamicResourceClient) makeURLSegments(name string) []string {
|
|||
|
||||
if len(name) > 0 {
|
||||
url = append(url, name)
|
||||
|
||||
// subresources only work on things with names
|
||||
if len(c.subresource) > 0 {
|
||||
url = append(url, c.subresource)
|
||||
}
|
||||
} else {
|
||||
if len(c.subresource) > 0 {
|
||||
panic("somehow snuck a subresource and an empty name. programmer error")
|
||||
}
|
||||
}
|
||||
|
||||
return url
|
||||
|
|
|
@ -225,6 +225,16 @@ func NewRootDeleteAction(resource schema.GroupVersionResource, name string) Dele
|
|||
return action
|
||||
}
|
||||
|
||||
func NewRootDeleteSubresourceAction(resource schema.GroupVersionResource, subresource string, name string) DeleteActionImpl {
|
||||
action := DeleteActionImpl{}
|
||||
action.Verb = "delete"
|
||||
action.Resource = resource
|
||||
action.Subresource = subresource
|
||||
action.Name = name
|
||||
|
||||
return action
|
||||
}
|
||||
|
||||
func NewDeleteAction(resource schema.GroupVersionResource, namespace, name string) DeleteActionImpl {
|
||||
action := DeleteActionImpl{}
|
||||
action.Verb = "delete"
|
||||
|
@ -235,6 +245,17 @@ func NewDeleteAction(resource schema.GroupVersionResource, namespace, name strin
|
|||
return action
|
||||
}
|
||||
|
||||
func NewDeleteSubresourceAction(resource schema.GroupVersionResource, subresource, namespace, name string) DeleteActionImpl {
|
||||
action := DeleteActionImpl{}
|
||||
action.Verb = "delete"
|
||||
action.Resource = resource
|
||||
action.Subresource = subresource
|
||||
action.Namespace = namespace
|
||||
action.Name = name
|
||||
|
||||
return action
|
||||
}
|
||||
|
||||
func NewRootDeleteCollectionAction(resource schema.GroupVersionResource, opts interface{}) DeleteCollectionActionImpl {
|
||||
action := DeleteCollectionActionImpl{}
|
||||
action.Verb = "delete-collection"
|
||||
|
|
|
@ -115,7 +115,7 @@ var _ = SIGDescribe("CustomResourceDefinition Watch", func() {
|
|||
})
|
||||
})
|
||||
|
||||
func watchCRWithName(crdResourceClient dynamic.DynamicResourceInterface, name string) (watch.Interface, error) {
|
||||
func watchCRWithName(crdResourceClient dynamic.ResourceInterface, name string) (watch.Interface, error) {
|
||||
return crdResourceClient.Watch(
|
||||
metav1.ListOptions{
|
||||
FieldSelector: "metadata.name=" + name,
|
||||
|
@ -124,7 +124,7 @@ func watchCRWithName(crdResourceClient dynamic.DynamicResourceInterface, name st
|
|||
)
|
||||
}
|
||||
|
||||
func instantiateCustomResource(instanceToCreate *unstructured.Unstructured, client dynamic.DynamicResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
|
||||
func instantiateCustomResource(instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
|
||||
createdInstance, err := client.Create(instanceToCreate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -150,11 +150,11 @@ func instantiateCustomResource(instanceToCreate *unstructured.Unstructured, clie
|
|||
return createdInstance, nil
|
||||
}
|
||||
|
||||
func deleteCustomResource(client dynamic.DynamicResourceInterface, name string) error {
|
||||
func deleteCustomResource(client dynamic.ResourceInterface, name string) error {
|
||||
return client.Delete(name, &metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
func newNamespacedCustomResourceClient(ns string, client dynamic.DynamicInterface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.DynamicResourceInterface {
|
||||
func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.ResourceInterface {
|
||||
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: crd.Spec.Version, Resource: crd.Spec.Names.Plural}
|
||||
|
||||
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
|
||||
|
|
|
@ -1081,7 +1081,7 @@ func registerMutatingWebhookForCustomResource(f *framework.Framework, context *c
|
|||
return func() { client.AdmissionregistrationV1beta1().MutatingWebhookConfigurations().Delete(configName, nil) }
|
||||
}
|
||||
|
||||
func testCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.DynamicResourceInterface) {
|
||||
func testCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.ResourceInterface) {
|
||||
By("Creating a custom resource that should be denied by the webhook")
|
||||
crInstance := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
|
@ -1104,7 +1104,7 @@ func testCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1
|
|||
}
|
||||
}
|
||||
|
||||
func testMutatingCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.DynamicResourceInterface) {
|
||||
func testMutatingCustomResourceWebhook(f *framework.Framework, crd *apiextensionsv1beta1.CustomResourceDefinition, customResourceClient dynamic.ResourceInterface) {
|
||||
By("Creating a custom resource that should be mutated by the webhook")
|
||||
cr := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
|
|
|
@ -38,7 +38,7 @@ type TestCrd struct {
|
|||
ApiVersion string
|
||||
ApiExtensionClient *crdclientset.Clientset
|
||||
Crd *apiextensionsv1beta1.CustomResourceDefinition
|
||||
DynamicClient dynamic.DynamicResourceInterface
|
||||
DynamicClient dynamic.ResourceInterface
|
||||
CleanUp CleanCrdFn
|
||||
}
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ type Framework struct {
|
|||
|
||||
InternalClientset *internalclientset.Clientset
|
||||
AggregatorClient *aggregatorclient.Clientset
|
||||
DynamicClient dynamic.DynamicInterface
|
||||
DynamicClient dynamic.Interface
|
||||
|
||||
ScalesGetter scaleclient.ScalesGetter
|
||||
|
||||
|
|
|
@ -506,7 +506,7 @@ func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersio
|
|||
}
|
||||
}
|
||||
|
||||
func SkipIfMissingResource(dynamicClient dynamic.DynamicInterface, gvr schema.GroupVersionResource, namespace string) {
|
||||
func SkipIfMissingResource(dynamicClient dynamic.Interface, gvr schema.GroupVersionResource, namespace string) {
|
||||
resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
|
||||
_, err := resourceClient.List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
|
@ -1086,7 +1086,7 @@ func CheckTestingNSDeletedExcept(c clientset.Interface, skip string) error {
|
|||
|
||||
// deleteNS deletes the provided namespace, waits for it to be completely deleted, and then checks
|
||||
// whether there are any pods remaining in a non-terminating state.
|
||||
func deleteNS(c clientset.Interface, dynamicClient dynamic.DynamicInterface, namespace string, timeout time.Duration) error {
|
||||
func deleteNS(c clientset.Interface, dynamicClient dynamic.Interface, namespace string, timeout time.Duration) error {
|
||||
startTime := time.Now()
|
||||
if err := c.CoreV1().Namespaces().Delete(namespace, nil); err != nil {
|
||||
return err
|
||||
|
@ -1232,7 +1232,7 @@ func isDynamicDiscoveryError(err error) bool {
|
|||
}
|
||||
|
||||
// hasRemainingContent checks if there is remaining content in the namespace via API discovery
|
||||
func hasRemainingContent(c clientset.Interface, dynamicClient dynamic.DynamicInterface, namespace string) (bool, error) {
|
||||
func hasRemainingContent(c clientset.Interface, dynamicClient dynamic.Interface, namespace string) (bool, error) {
|
||||
// some tests generate their own framework.Client rather than the default
|
||||
// TODO: ensure every test call has a configured dynamicClient
|
||||
if dynamicClient == nil {
|
||||
|
|
|
@ -46,29 +46,12 @@ func TestDynamicClient(t *testing.T) {
|
|||
}
|
||||
|
||||
client := clientset.NewForConfigOrDie(config)
|
||||
dynamicClient, err := dynamic.NewClient(config, *gv)
|
||||
_ = dynamicClient
|
||||
dynamicClient, err := dynamic.NewForConfig(config)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error creating dynamic client: %v", err)
|
||||
}
|
||||
|
||||
// Find the Pod resource
|
||||
resources, err := client.Discovery().ServerResourcesForGroupVersion(gv.String())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error listing resources: %v", err)
|
||||
}
|
||||
|
||||
var resource metav1.APIResource
|
||||
for _, r := range resources.APIResources {
|
||||
if r.Kind == "Pod" {
|
||||
resource = r
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(resource.Name) == 0 {
|
||||
t.Fatalf("could not find the pod resource in group/version %q", gv.String())
|
||||
}
|
||||
resource := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
||||
|
||||
// Create a Pod with the normal client
|
||||
pod := &v1.Pod{
|
||||
|
@ -91,11 +74,7 @@ func TestDynamicClient(t *testing.T) {
|
|||
}
|
||||
|
||||
// check dynamic list
|
||||
obj, err := dynamicClient.Resource(&resource, ns.Name).List(metav1.ListOptions{})
|
||||
unstructuredList, ok := obj.(*unstructured.UnstructuredList)
|
||||
if !ok {
|
||||
t.Fatalf("expected *unstructured.UnstructuredList, got %#v", obj)
|
||||
}
|
||||
unstructuredList, err := dynamicClient.Resource(resource).Namespace(ns.Name).List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error when listing pods: %v", err)
|
||||
}
|
||||
|
@ -114,7 +93,7 @@ func TestDynamicClient(t *testing.T) {
|
|||
}
|
||||
|
||||
// check dynamic get
|
||||
unstruct, err := dynamicClient.Resource(&resource, ns.Name).Get(actual.Name, metav1.GetOptions{})
|
||||
unstruct, err := dynamicClient.Resource(resource).Namespace(ns.Name).Get(actual.Name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error when getting pod %q: %v", actual.Name, err)
|
||||
}
|
||||
|
@ -129,7 +108,7 @@ func TestDynamicClient(t *testing.T) {
|
|||
}
|
||||
|
||||
// delete the pod dynamically
|
||||
err = dynamicClient.Resource(&resource, ns.Name).Delete(actual.Name, nil)
|
||||
err = dynamicClient.Resource(resource).Namespace(ns.Name).Delete(actual.Name, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error when deleting pod: %v", err)
|
||||
}
|
||||
|
|
|
@ -168,9 +168,9 @@ func link(t *testing.T, owner, dependent metav1.Object) {
|
|||
|
||||
func createRandomCustomResourceDefinition(
|
||||
t *testing.T, apiExtensionClient apiextensionsclientset.Interface,
|
||||
dynamicClient dynamic.DynamicInterface,
|
||||
dynamicClient dynamic.Interface,
|
||||
namespace string,
|
||||
) (*apiextensionsv1beta1.CustomResourceDefinition, dynamic.DynamicResourceInterface) {
|
||||
) (*apiextensionsv1beta1.CustomResourceDefinition, dynamic.ResourceInterface) {
|
||||
// Create a random custom resource definition and ensure it's available for
|
||||
// use.
|
||||
definition := apiextensionstestserver.NewRandomNameCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
|
||||
|
@ -193,7 +193,7 @@ type testContext struct {
|
|||
gc *garbagecollector.GarbageCollector
|
||||
clientSet clientset.Interface
|
||||
apiExtensionClient apiextensionsclientset.Interface
|
||||
dynamicClient dynamic.DynamicInterface
|
||||
dynamicClient dynamic.Interface
|
||||
startGC func(workers int)
|
||||
// syncPeriod is how often the GC started with startGC will be resynced.
|
||||
syncPeriod time.Duration
|
||||
|
|
|
@ -150,14 +150,12 @@ func TestCRD(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Logf("Trying to access foos.cr.bar.com with dynamic client")
|
||||
barComConfig := *result.ClientConfig
|
||||
barComConfig.GroupVersion = &schema.GroupVersion{Group: "cr.bar.com", Version: "v1"}
|
||||
barComConfig.APIPath = "/apis"
|
||||
barComClient, err := dynamic.NewClient(&barComConfig, *barComConfig.GroupVersion)
|
||||
dynamicClient, err := dynamic.NewForConfig(result.ClientConfig)
|
||||
if err != nil {
|
||||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
_, err = barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").List(metav1.ListOptions{})
|
||||
fooResource := schema.GroupVersionResource{Group: "cr.bar.com", Version: "v1", Resource: "foos"}
|
||||
_, err = dynamicClient.Resource(fooResource).Namespace("default").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("Failed to list foos.cr.bar.com instances: %v", err)
|
||||
}
|
||||
|
@ -201,7 +199,7 @@ func TestCRD(t *testing.T) {
|
|||
}
|
||||
createErr := make(chan error, 1)
|
||||
go func() {
|
||||
_, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Create(unstructuredFoo)
|
||||
_, err := dynamicClient.Resource(fooResource).Namespace("default").Create(unstructuredFoo)
|
||||
t.Logf("Foo instance create returned: %v", err)
|
||||
if err != nil {
|
||||
createErr <- err
|
||||
|
@ -216,7 +214,7 @@ func TestCRD(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Logf("Checking that Foo instance is visible with IncludeUninitialized=true")
|
||||
_, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Get(foo.ObjectMeta.Name, metav1.GetOptions{
|
||||
_, err := dynamicClient.Resource(fooResource).Namespace("default").Get(foo.ObjectMeta.Name, metav1.GetOptions{
|
||||
IncludeUninitialized: true,
|
||||
})
|
||||
switch {
|
||||
|
@ -237,7 +235,7 @@ func TestCRD(t *testing.T) {
|
|||
for i := 0; i < 10; i++ {
|
||||
// would love to replace the following with a patch, but removing strings from the intitializer array
|
||||
// is not what JSON (Merge) patch authors had in mind.
|
||||
fooUnstructured, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Get(foo.ObjectMeta.Name, metav1.GetOptions{
|
||||
fooUnstructured, err := dynamicClient.Resource(fooResource).Namespace("default").Get(foo.ObjectMeta.Name, metav1.GetOptions{
|
||||
IncludeUninitialized: true,
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -274,7 +272,7 @@ func TestCRD(t *testing.T) {
|
|||
}
|
||||
fooUnstructured.UnmarshalJSON(bs)
|
||||
|
||||
_, err = barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Update(fooUnstructured)
|
||||
_, err = dynamicClient.Resource(fooResource).Namespace("default").Update(fooUnstructured)
|
||||
if err != nil && !errors.IsConflict(err) {
|
||||
t.Fatalf("Failed to update Foo instance: %v", err)
|
||||
} else if err == nil {
|
||||
|
@ -287,7 +285,7 @@ func TestCRD(t *testing.T) {
|
|||
}
|
||||
|
||||
t.Logf("Checking that Foo instance is visible after removing the initializer")
|
||||
if _, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Get(foo.ObjectMeta.Name, metav1.GetOptions{}); err != nil {
|
||||
if _, err := dynamicClient.Resource(fooResource).Namespace("default").Get(foo.ObjectMeta.Name, metav1.GetOptions{}); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue