838 lines
29 KiB
Go
838 lines
29 KiB
Go
/*
|
|
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 testing
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
"k8s.io/apimachinery/pkg/api/meta/testrestmapper"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/conversion"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/apimachinery/pkg/runtime/serializer"
|
|
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
|
"k8s.io/cli-runtime/pkg/genericclioptions"
|
|
"k8s.io/cli-runtime/pkg/resource"
|
|
"k8s.io/client-go/discovery"
|
|
diskcached "k8s.io/client-go/discovery/cached/disk"
|
|
"k8s.io/client-go/dynamic"
|
|
fakedynamic "k8s.io/client-go/dynamic/fake"
|
|
"k8s.io/client-go/kubernetes"
|
|
openapiclient "k8s.io/client-go/openapi"
|
|
"k8s.io/client-go/openapi/openapitest"
|
|
restclient "k8s.io/client-go/rest"
|
|
"k8s.io/client-go/rest/fake"
|
|
"k8s.io/client-go/restmapper"
|
|
scaleclient "k8s.io/client-go/scale"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
cmdutil "k8s.io/kubectl/pkg/cmd/util"
|
|
"k8s.io/kubectl/pkg/scheme"
|
|
"k8s.io/kubectl/pkg/util/openapi"
|
|
openapitesting "k8s.io/kubectl/pkg/util/openapi/testing"
|
|
"k8s.io/kubectl/pkg/validation"
|
|
)
|
|
|
|
// InternalType is the schema for internal type
|
|
// +k8s:deepcopy-gen=true
|
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
type InternalType struct {
|
|
Kind string
|
|
APIVersion string
|
|
|
|
Name string
|
|
}
|
|
|
|
// ExternalType is the schema for external type
|
|
// +k8s:deepcopy-gen=true
|
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
type ExternalType struct {
|
|
Kind string `json:"kind"`
|
|
APIVersion string `json:"apiVersion"`
|
|
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// ExternalType2 is another schema for external type
|
|
// +k8s:deepcopy-gen=true
|
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
type ExternalType2 struct {
|
|
Kind string `json:"kind"`
|
|
APIVersion string `json:"apiVersion"`
|
|
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// GetObjectKind returns the ObjectKind schema
|
|
func (obj *InternalType) GetObjectKind() schema.ObjectKind { return obj }
|
|
|
|
// SetGroupVersionKind sets the version and kind
|
|
func (obj *InternalType) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
|
}
|
|
|
|
// GroupVersionKind returns GroupVersionKind schema
|
|
func (obj *InternalType) GroupVersionKind() schema.GroupVersionKind {
|
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
|
}
|
|
|
|
// GetObjectKind returns the ObjectKind schema
|
|
func (obj *ExternalType) GetObjectKind() schema.ObjectKind { return obj }
|
|
|
|
// SetGroupVersionKind returns the GroupVersionKind schema
|
|
func (obj *ExternalType) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
|
}
|
|
|
|
// GroupVersionKind returns the GroupVersionKind schema
|
|
func (obj *ExternalType) GroupVersionKind() schema.GroupVersionKind {
|
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
|
}
|
|
|
|
// GetObjectKind returns the ObjectKind schema
|
|
func (obj *ExternalType2) GetObjectKind() schema.ObjectKind { return obj }
|
|
|
|
// SetGroupVersionKind sets the API version and obj kind from schema
|
|
func (obj *ExternalType2) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
|
}
|
|
|
|
// GroupVersionKind returns the FromAPIVersionAndKind schema
|
|
func (obj *ExternalType2) GroupVersionKind() schema.GroupVersionKind {
|
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
|
}
|
|
|
|
// NewInternalType returns an initialized InternalType instance
|
|
func NewInternalType(kind, apiversion, name string) *InternalType {
|
|
item := InternalType{Kind: kind,
|
|
APIVersion: apiversion,
|
|
Name: name}
|
|
return &item
|
|
}
|
|
|
|
func convertInternalTypeToExternalType(in *InternalType, out *ExternalType, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
return nil
|
|
}
|
|
|
|
func convertInternalTypeToExternalType2(in *InternalType, out *ExternalType2, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
return nil
|
|
}
|
|
|
|
func convertExternalTypeToInternalType(in *ExternalType, out *InternalType, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
return nil
|
|
}
|
|
|
|
func convertExternalType2ToInternalType(in *ExternalType2, out *InternalType, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
return nil
|
|
}
|
|
|
|
// InternalNamespacedType schema for internal namespaced types
|
|
// +k8s:deepcopy-gen=true
|
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
type InternalNamespacedType struct {
|
|
Kind string
|
|
APIVersion string
|
|
|
|
Name string
|
|
Namespace string
|
|
}
|
|
|
|
// ExternalNamespacedType schema for external namespaced types
|
|
// +k8s:deepcopy-gen=true
|
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
type ExternalNamespacedType struct {
|
|
Kind string `json:"kind"`
|
|
APIVersion string `json:"apiVersion"`
|
|
|
|
Name string `json:"name"`
|
|
Namespace string `json:"namespace"`
|
|
}
|
|
|
|
// ExternalNamespacedType2 schema for external namespaced types
|
|
// +k8s:deepcopy-gen=true
|
|
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
|
|
type ExternalNamespacedType2 struct {
|
|
Kind string `json:"kind"`
|
|
APIVersion string `json:"apiVersion"`
|
|
|
|
Name string `json:"name"`
|
|
Namespace string `json:"namespace"`
|
|
}
|
|
|
|
// GetObjectKind returns the ObjectKind schema
|
|
func (obj *InternalNamespacedType) GetObjectKind() schema.ObjectKind { return obj }
|
|
|
|
// SetGroupVersionKind sets the API group and kind from schema
|
|
func (obj *InternalNamespacedType) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
|
}
|
|
|
|
// GroupVersionKind returns the GroupVersionKind schema
|
|
func (obj *InternalNamespacedType) GroupVersionKind() schema.GroupVersionKind {
|
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
|
}
|
|
|
|
// GetObjectKind returns the ObjectKind schema
|
|
func (obj *ExternalNamespacedType) GetObjectKind() schema.ObjectKind { return obj }
|
|
|
|
// SetGroupVersionKind sets the API version and kind from schema
|
|
func (obj *ExternalNamespacedType) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
|
}
|
|
|
|
// GroupVersionKind returns the GroupVersionKind schema
|
|
func (obj *ExternalNamespacedType) GroupVersionKind() schema.GroupVersionKind {
|
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
|
}
|
|
|
|
// GetObjectKind returns the ObjectKind schema
|
|
func (obj *ExternalNamespacedType2) GetObjectKind() schema.ObjectKind { return obj }
|
|
|
|
// SetGroupVersionKind sets the API version and kind from schema
|
|
func (obj *ExternalNamespacedType2) SetGroupVersionKind(gvk schema.GroupVersionKind) {
|
|
obj.APIVersion, obj.Kind = gvk.ToAPIVersionAndKind()
|
|
}
|
|
|
|
// GroupVersionKind returns the GroupVersionKind schema
|
|
func (obj *ExternalNamespacedType2) GroupVersionKind() schema.GroupVersionKind {
|
|
return schema.FromAPIVersionAndKind(obj.APIVersion, obj.Kind)
|
|
}
|
|
|
|
// NewInternalNamespacedType returns an initialized instance of InternalNamespacedType
|
|
func NewInternalNamespacedType(kind, apiversion, name, namespace string) *InternalNamespacedType {
|
|
item := InternalNamespacedType{Kind: kind,
|
|
APIVersion: apiversion,
|
|
Name: name,
|
|
Namespace: namespace}
|
|
return &item
|
|
}
|
|
|
|
func convertInternalNamespacedTypeToExternalNamespacedType(in *InternalNamespacedType, out *ExternalNamespacedType, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
out.Namespace = in.Namespace
|
|
return nil
|
|
}
|
|
|
|
func convertInternalNamespacedTypeToExternalNamespacedType2(in *InternalNamespacedType, out *ExternalNamespacedType2, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
out.Namespace = in.Namespace
|
|
return nil
|
|
}
|
|
|
|
func convertExternalNamespacedTypeToInternalNamespacedType(in *ExternalNamespacedType, out *InternalNamespacedType, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
out.Namespace = in.Namespace
|
|
return nil
|
|
}
|
|
|
|
func convertExternalNamespacedType2ToInternalNamespacedType(in *ExternalNamespacedType2, out *InternalNamespacedType, s conversion.Scope) error {
|
|
out.Kind = in.Kind
|
|
out.APIVersion = in.APIVersion
|
|
out.Name = in.Name
|
|
out.Namespace = in.Namespace
|
|
return nil
|
|
}
|
|
|
|
// ValidVersion of API
|
|
var ValidVersion = "v1"
|
|
|
|
// InternalGV is the internal group version object
|
|
var InternalGV = schema.GroupVersion{Group: "apitest", Version: runtime.APIVersionInternal}
|
|
|
|
// UnlikelyGV is a group version object for unrecognised version
|
|
var UnlikelyGV = schema.GroupVersion{Group: "apitest", Version: "unlikelyversion"}
|
|
|
|
// ValidVersionGV is the valid group version object
|
|
var ValidVersionGV = schema.GroupVersion{Group: "apitest", Version: ValidVersion}
|
|
|
|
// NewExternalScheme returns required objects for ExternalScheme
|
|
func NewExternalScheme() (*runtime.Scheme, meta.RESTMapper, runtime.Codec) {
|
|
scheme := runtime.NewScheme()
|
|
mapper, codec := AddToScheme(scheme)
|
|
return scheme, mapper, codec
|
|
}
|
|
|
|
func registerConversions(s *runtime.Scheme) error {
|
|
if err := s.AddConversionFunc((*InternalType)(nil), (*ExternalType)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertInternalTypeToExternalType(a.(*InternalType), b.(*ExternalType), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*InternalType)(nil), (*ExternalType2)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertInternalTypeToExternalType2(a.(*InternalType), b.(*ExternalType2), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*ExternalType)(nil), (*InternalType)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertExternalTypeToInternalType(a.(*ExternalType), b.(*InternalType), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*ExternalType2)(nil), (*InternalType)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertExternalType2ToInternalType(a.(*ExternalType2), b.(*InternalType), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*InternalNamespacedType)(nil), (*ExternalNamespacedType)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertInternalNamespacedTypeToExternalNamespacedType(a.(*InternalNamespacedType), b.(*ExternalNamespacedType), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*InternalNamespacedType)(nil), (*ExternalNamespacedType2)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertInternalNamespacedTypeToExternalNamespacedType2(a.(*InternalNamespacedType), b.(*ExternalNamespacedType2), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*ExternalNamespacedType)(nil), (*InternalNamespacedType)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertExternalNamespacedTypeToInternalNamespacedType(a.(*ExternalNamespacedType), b.(*InternalNamespacedType), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
if err := s.AddConversionFunc((*ExternalNamespacedType2)(nil), (*InternalNamespacedType)(nil), func(a, b interface{}, scope conversion.Scope) error {
|
|
return convertExternalNamespacedType2ToInternalNamespacedType(a.(*ExternalNamespacedType2), b.(*InternalNamespacedType), scope)
|
|
}); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AddToScheme adds required objects into scheme
|
|
func AddToScheme(scheme *runtime.Scheme) (meta.RESTMapper, runtime.Codec) {
|
|
scheme.AddKnownTypeWithName(InternalGV.WithKind("Type"), &InternalType{})
|
|
scheme.AddKnownTypeWithName(UnlikelyGV.WithKind("Type"), &ExternalType{})
|
|
// This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
|
scheme.AddKnownTypeWithName(ValidVersionGV.WithKind("Type"), &ExternalType2{})
|
|
|
|
scheme.AddKnownTypeWithName(InternalGV.WithKind("NamespacedType"), &InternalNamespacedType{})
|
|
scheme.AddKnownTypeWithName(UnlikelyGV.WithKind("NamespacedType"), &ExternalNamespacedType{})
|
|
// This tests that kubectl will not confuse the external scheme with the internal scheme, even when they accidentally have versions of the same name.
|
|
scheme.AddKnownTypeWithName(ValidVersionGV.WithKind("NamespacedType"), &ExternalNamespacedType2{})
|
|
|
|
utilruntime.Must(registerConversions(scheme))
|
|
|
|
codecs := serializer.NewCodecFactory(scheme)
|
|
codec := codecs.LegacyCodec(UnlikelyGV)
|
|
mapper := meta.NewDefaultRESTMapper([]schema.GroupVersion{UnlikelyGV, ValidVersionGV})
|
|
for _, gv := range []schema.GroupVersion{UnlikelyGV, ValidVersionGV} {
|
|
for kind := range scheme.KnownTypes(gv) {
|
|
gvk := gv.WithKind(kind)
|
|
|
|
scope := meta.RESTScopeNamespace
|
|
mapper.Add(gvk, scope)
|
|
}
|
|
}
|
|
|
|
return mapper, codec
|
|
}
|
|
|
|
type FakeCachedDiscoveryClient struct {
|
|
discovery.DiscoveryInterface
|
|
Groups []*metav1.APIGroup
|
|
Resources []*metav1.APIResourceList
|
|
PreferredResources []*metav1.APIResourceList
|
|
Invalidations int
|
|
}
|
|
|
|
func NewFakeCachedDiscoveryClient() *FakeCachedDiscoveryClient {
|
|
return &FakeCachedDiscoveryClient{
|
|
Groups: []*metav1.APIGroup{},
|
|
Resources: []*metav1.APIResourceList{},
|
|
PreferredResources: []*metav1.APIResourceList{},
|
|
Invalidations: 0,
|
|
}
|
|
}
|
|
|
|
func (d *FakeCachedDiscoveryClient) Fresh() bool {
|
|
return true
|
|
}
|
|
|
|
func (d *FakeCachedDiscoveryClient) Invalidate() {
|
|
d.Invalidations++
|
|
}
|
|
|
|
func (d *FakeCachedDiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
|
|
return d.Groups, d.Resources, nil
|
|
}
|
|
|
|
func (d *FakeCachedDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
|
|
groupList := &metav1.APIGroupList{Groups: []metav1.APIGroup{}}
|
|
for _, g := range d.Groups {
|
|
groupList.Groups = append(groupList.Groups, *g)
|
|
}
|
|
return groupList, nil
|
|
}
|
|
|
|
func (d *FakeCachedDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
|
|
return d.PreferredResources, nil
|
|
}
|
|
|
|
// TestFactory extends cmdutil.Factory
|
|
type TestFactory struct {
|
|
cmdutil.Factory
|
|
|
|
kubeConfigFlags *genericclioptions.TestConfigFlags
|
|
|
|
Client RESTClient
|
|
ScaleGetter scaleclient.ScalesGetter
|
|
UnstructuredClient RESTClient
|
|
ClientConfigVal *restclient.Config
|
|
FakeDynamicClient *fakedynamic.FakeDynamicClient
|
|
|
|
tempConfigFile *os.File
|
|
|
|
UnstructuredClientForMappingFunc resource.FakeClientFunc
|
|
OpenAPISchemaFunc func() (openapi.Resources, error)
|
|
OpenAPIV3ClientFunc func() (openapiclient.Client, error)
|
|
}
|
|
|
|
// NewTestFactory returns an initialized TestFactory instance
|
|
func NewTestFactory() *TestFactory {
|
|
// specify an optionalClientConfig to explicitly use in testing
|
|
// to avoid polluting an existing user config.
|
|
tmpFile, err := os.CreateTemp(os.TempDir(), "cmdtests_temp")
|
|
if err != nil {
|
|
panic(fmt.Sprintf("unable to create a fake client config: %v", err))
|
|
}
|
|
|
|
loadingRules := &clientcmd.ClientConfigLoadingRules{
|
|
Precedence: []string{tmpFile.Name()},
|
|
MigrationRules: map[string]string{},
|
|
}
|
|
|
|
overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmdapi.Cluster{Server: "http://localhost:8080"}}
|
|
fallbackReader := bytes.NewBuffer([]byte{})
|
|
clientConfig := clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, fallbackReader)
|
|
|
|
configFlags := genericclioptions.NewTestConfigFlags().
|
|
WithClientConfig(clientConfig).
|
|
WithRESTMapper(testRESTMapper())
|
|
|
|
restConfig, err := clientConfig.ClientConfig()
|
|
if err != nil {
|
|
panic(fmt.Sprintf("unable to create a fake restclient config: %v", err))
|
|
}
|
|
|
|
return &TestFactory{
|
|
Factory: cmdutil.NewFactory(configFlags),
|
|
kubeConfigFlags: configFlags,
|
|
FakeDynamicClient: fakedynamic.NewSimpleDynamicClient(scheme.Scheme),
|
|
tempConfigFile: tmpFile,
|
|
|
|
ClientConfigVal: restConfig,
|
|
}
|
|
}
|
|
|
|
// WithNamespace is used to mention namespace reactively
|
|
func (f *TestFactory) WithNamespace(ns string) *TestFactory {
|
|
f.kubeConfigFlags.WithNamespace(ns)
|
|
return f
|
|
}
|
|
|
|
// WithClientConfig sets the client config to use
|
|
func (f *TestFactory) WithClientConfig(clientConfig clientcmd.ClientConfig) *TestFactory {
|
|
f.kubeConfigFlags.WithClientConfig(clientConfig)
|
|
return f
|
|
}
|
|
|
|
func (f *TestFactory) WithDiscoveryClient(discoveryClient discovery.CachedDiscoveryInterface) *TestFactory {
|
|
f.kubeConfigFlags.WithDiscoveryClient(discoveryClient)
|
|
return f
|
|
}
|
|
|
|
// Cleanup cleans up TestFactory temp config file
|
|
func (f *TestFactory) Cleanup() {
|
|
if f.tempConfigFile == nil {
|
|
return
|
|
}
|
|
|
|
f.tempConfigFile.Close()
|
|
os.Remove(f.tempConfigFile.Name())
|
|
}
|
|
|
|
// ToRESTConfig is used to get ClientConfigVal from a TestFactory
|
|
func (f *TestFactory) ToRESTConfig() (*restclient.Config, error) {
|
|
return f.ClientConfigVal, nil
|
|
}
|
|
|
|
// ClientForMapping is used to Client from a TestFactory
|
|
func (f *TestFactory) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
|
return f.Client, nil
|
|
}
|
|
|
|
// PathOptions returns a new PathOptions with a temp file
|
|
func (f *TestFactory) PathOptions() *clientcmd.PathOptions {
|
|
pathOptions := clientcmd.NewDefaultPathOptions()
|
|
pathOptions.GlobalFile = f.tempConfigFile.Name()
|
|
pathOptions.EnvVar = ""
|
|
return pathOptions
|
|
}
|
|
|
|
// PathOptionsWithConfig writes a config to a temp file and returns PathOptions
|
|
func (f *TestFactory) PathOptionsWithConfig(config clientcmdapi.Config) (*clientcmd.PathOptions, error) {
|
|
pathOptions := f.PathOptions()
|
|
err := clientcmd.WriteToFile(config, pathOptions.GlobalFile)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return pathOptions, nil
|
|
}
|
|
|
|
// UnstructuredClientForMapping is used to get UnstructuredClient from a TestFactory
|
|
func (f *TestFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
|
|
if f.UnstructuredClientForMappingFunc != nil {
|
|
return f.UnstructuredClientForMappingFunc(mapping.GroupVersionKind.GroupVersion())
|
|
}
|
|
return f.UnstructuredClient, nil
|
|
}
|
|
|
|
// Validator returns a validation schema
|
|
func (f *TestFactory) Validator(validateDirective string) (validation.Schema, error) {
|
|
return validation.NullSchema{}, nil
|
|
}
|
|
|
|
// OpenAPISchema returns openapi resources
|
|
func (f *TestFactory) OpenAPISchema() (openapi.Resources, error) {
|
|
if f.OpenAPISchemaFunc != nil {
|
|
return f.OpenAPISchemaFunc()
|
|
}
|
|
return openapitesting.EmptyResources{}, nil
|
|
}
|
|
|
|
func (f *TestFactory) OpenAPIV3Client() (openapiclient.Client, error) {
|
|
if f.OpenAPIV3ClientFunc != nil {
|
|
return f.OpenAPIV3ClientFunc()
|
|
}
|
|
return openapitest.NewFakeClient(), nil
|
|
}
|
|
|
|
// NewBuilder returns an initialized resource.Builder instance
|
|
func (f *TestFactory) NewBuilder() *resource.Builder {
|
|
return resource.NewFakeBuilder(
|
|
func(version schema.GroupVersion) (resource.RESTClient, error) {
|
|
if f.UnstructuredClientForMappingFunc != nil {
|
|
return f.UnstructuredClientForMappingFunc(version)
|
|
}
|
|
if f.UnstructuredClient != nil {
|
|
return f.UnstructuredClient, nil
|
|
}
|
|
return f.Client, nil
|
|
},
|
|
f.ToRESTMapper,
|
|
func() (restmapper.CategoryExpander, error) {
|
|
return resource.FakeCategoryExpander, nil
|
|
},
|
|
)
|
|
}
|
|
|
|
// KubernetesClientSet initializes and returns the Clientset using TestFactory
|
|
func (f *TestFactory) KubernetesClientSet() (*kubernetes.Clientset, error) {
|
|
fakeClient := f.Client.(*fake.RESTClient)
|
|
clientset := kubernetes.NewForConfigOrDie(f.ClientConfigVal)
|
|
|
|
clientset.CoreV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AuthorizationV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AuthorizationV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AuthorizationV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AuthorizationV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AuthenticationV1alpha1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AutoscalingV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AutoscalingV2().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.BatchV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.CertificatesV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.CertificatesV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.ExtensionsV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.RbacV1alpha1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.RbacV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.StorageV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.StorageV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AppsV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AppsV1beta2().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.AppsV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.PolicyV1beta1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.PolicyV1().RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
clientset.DiscoveryClient.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
|
|
return clientset, nil
|
|
}
|
|
|
|
// DynamicClient returns a dynamic client from TestFactory
|
|
func (f *TestFactory) DynamicClient() (dynamic.Interface, error) {
|
|
if f.FakeDynamicClient != nil {
|
|
return f.FakeDynamicClient, nil
|
|
}
|
|
return f.Factory.DynamicClient()
|
|
}
|
|
|
|
// RESTClient returns a REST client from TestFactory
|
|
func (f *TestFactory) RESTClient() (*restclient.RESTClient, error) {
|
|
// Swap out the HTTP client out of the client with the fake's version.
|
|
fakeClient := f.Client.(*fake.RESTClient)
|
|
restClient, err := restclient.RESTClientFor(f.ClientConfigVal)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
restClient.Client = fakeClient.Client
|
|
return restClient, nil
|
|
}
|
|
|
|
// DiscoveryClient returns a discovery client from TestFactory
|
|
func (f *TestFactory) DiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
|
|
fakeClient := f.Client.(*fake.RESTClient)
|
|
|
|
cacheDir := filepath.Join("", ".kube", "cache", "discovery")
|
|
cachedClient, err := diskcached.NewCachedDiscoveryClientForConfig(f.ClientConfigVal, cacheDir, "", time.Duration(10*time.Minute))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cachedClient.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
|
|
|
return cachedClient, nil
|
|
}
|
|
|
|
func testRESTMapper() meta.RESTMapper {
|
|
groupResources := testDynamicResources()
|
|
mapper := restmapper.NewDiscoveryRESTMapper(groupResources)
|
|
// for backwards compatibility with existing tests, allow rest mappings from the scheme to show up
|
|
// TODO: make this opt-in?
|
|
mapper = meta.FirstHitRESTMapper{
|
|
MultiRESTMapper: meta.MultiRESTMapper{
|
|
mapper,
|
|
testrestmapper.TestOnlyStaticRESTMapper(scheme.Scheme),
|
|
},
|
|
}
|
|
|
|
fakeDs := NewFakeCachedDiscoveryClient()
|
|
expander := restmapper.NewShortcutExpander(mapper, fakeDs, nil)
|
|
return expander
|
|
}
|
|
|
|
// ScaleClient returns the ScalesGetter from a TestFactory
|
|
func (f *TestFactory) ScaleClient() (scaleclient.ScalesGetter, error) {
|
|
return f.ScaleGetter, nil
|
|
}
|
|
|
|
func testDynamicResources() []*restmapper.APIGroupResources {
|
|
return []*restmapper.APIGroupResources{
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1": {
|
|
{Name: "pods", Namespaced: true, Kind: "Pod"},
|
|
{Name: "services", Namespaced: true, Kind: "Service"},
|
|
{Name: "replicationcontrollers", Namespaced: true, Kind: "ReplicationController"},
|
|
{Name: "componentstatuses", Namespaced: false, Kind: "ComponentStatus"},
|
|
{Name: "nodes", Namespaced: false, Kind: "Node"},
|
|
{Name: "secrets", Namespaced: true, Kind: "Secret"},
|
|
{Name: "configmaps", Namespaced: true, Kind: "ConfigMap"},
|
|
{Name: "namespacedtype", Namespaced: true, Kind: "NamespacedType"},
|
|
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
|
|
{Name: "resourcequotas", Namespaced: true, Kind: "ResourceQuota"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "extensions",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1beta1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1beta1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1beta1": {
|
|
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
|
{Name: "replicasets", Namespaced: true, Kind: "ReplicaSet"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "apps",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1beta1"},
|
|
{Version: "v1beta2"},
|
|
{Version: "v1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1beta1": {
|
|
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
|
{Name: "replicasets", Namespaced: true, Kind: "ReplicaSet"},
|
|
},
|
|
"v1beta2": {
|
|
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
|
},
|
|
"v1": {
|
|
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
|
|
{Name: "replicasets", Namespaced: true, Kind: "ReplicaSet"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "batch",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1beta1"},
|
|
{Version: "v1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1beta1": {
|
|
{Name: "cronjobs", Namespaced: true, Kind: "CronJob"},
|
|
},
|
|
"v1": {
|
|
{Name: "jobs", Namespaced: true, Kind: "Job"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "autoscaling",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1"},
|
|
{Version: "v2"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1": {
|
|
{Name: "horizontalpodautoscalers", Namespaced: true, Kind: "HorizontalPodAutoscaler"},
|
|
},
|
|
"v2": {
|
|
{Name: "horizontalpodautoscalers", Namespaced: true, Kind: "HorizontalPodAutoscaler"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "storage.k8s.io",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1beta1"},
|
|
{Version: "v0"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1beta1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1beta1": {
|
|
{Name: "storageclasses", Namespaced: false, Kind: "StorageClass"},
|
|
},
|
|
// bogus version of a known group/version/resource to make sure kubectl falls back to generic object mode
|
|
"v0": {
|
|
{Name: "storageclasses", Namespaced: false, Kind: "StorageClass"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "rbac.authorization.k8s.io",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1beta1"},
|
|
{Version: "v1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1": {
|
|
{Name: "clusterroles", Namespaced: false, Kind: "ClusterRole"},
|
|
},
|
|
"v1beta1": {
|
|
{Name: "clusterrolebindings", Namespaced: false, Kind: "ClusterRoleBinding"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "company.com",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{Version: "v1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1": {
|
|
{Name: "bars", Namespaced: true, Kind: "Bar"},
|
|
{Name: "applysets", Namespaced: false, Kind: "ApplySet"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "unit-test.test.com",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{GroupVersion: "unit-test.test.com/v1", Version: "v1"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
|
GroupVersion: "unit-test.test.com/v1",
|
|
Version: "v1"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"v1": {
|
|
{Name: "widgets", Namespaced: true, Kind: "Widget"},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
Group: metav1.APIGroup{
|
|
Name: "apitest",
|
|
Versions: []metav1.GroupVersionForDiscovery{
|
|
{GroupVersion: "apitest/unlikelyversion", Version: "unlikelyversion"},
|
|
},
|
|
PreferredVersion: metav1.GroupVersionForDiscovery{
|
|
GroupVersion: "apitest/unlikelyversion",
|
|
Version: "unlikelyversion"},
|
|
},
|
|
VersionedResources: map[string][]metav1.APIResource{
|
|
"unlikelyversion": {
|
|
{Name: "types", SingularName: "type", Namespaced: false, Kind: "Type"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
}
|