...

Source file src/k8s.io/kubectl/pkg/cmd/util/factory_client_access.go

Documentation: k8s.io/kubectl/pkg/cmd/util

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // this file contains factories with no other dependencies
    18  
    19  package util
    20  
    21  import (
    22  	"errors"
    23  	"sync"
    24  
    25  	corev1 "k8s.io/api/core/v1"
    26  	"k8s.io/apimachinery/pkg/api/meta"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/cli-runtime/pkg/genericclioptions"
    29  	"k8s.io/cli-runtime/pkg/resource"
    30  	"k8s.io/client-go/discovery"
    31  	"k8s.io/client-go/dynamic"
    32  	"k8s.io/client-go/kubernetes"
    33  	openapiclient "k8s.io/client-go/openapi"
    34  	"k8s.io/client-go/openapi/cached"
    35  	restclient "k8s.io/client-go/rest"
    36  	"k8s.io/client-go/tools/clientcmd"
    37  	"k8s.io/kubectl/pkg/util/openapi"
    38  	"k8s.io/kubectl/pkg/validation"
    39  )
    40  
    41  type factoryImpl struct {
    42  	clientGetter genericclioptions.RESTClientGetter
    43  
    44  	// Caches OpenAPI document and parsed resources
    45  	openAPIParser *openapi.CachedOpenAPIParser
    46  	oapi          *openapi.CachedOpenAPIGetter
    47  	parser        sync.Once
    48  	getter        sync.Once
    49  }
    50  
    51  func NewFactory(clientGetter genericclioptions.RESTClientGetter) Factory {
    52  	if clientGetter == nil {
    53  		panic("attempt to instantiate client_access_factory with nil clientGetter")
    54  	}
    55  	f := &factoryImpl{
    56  		clientGetter: clientGetter,
    57  	}
    58  
    59  	return f
    60  }
    61  
    62  func (f *factoryImpl) ToRESTConfig() (*restclient.Config, error) {
    63  	return f.clientGetter.ToRESTConfig()
    64  }
    65  
    66  func (f *factoryImpl) ToRESTMapper() (meta.RESTMapper, error) {
    67  	return f.clientGetter.ToRESTMapper()
    68  }
    69  
    70  func (f *factoryImpl) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
    71  	return f.clientGetter.ToDiscoveryClient()
    72  }
    73  
    74  func (f *factoryImpl) ToRawKubeConfigLoader() clientcmd.ClientConfig {
    75  	return f.clientGetter.ToRawKubeConfigLoader()
    76  }
    77  
    78  func (f *factoryImpl) KubernetesClientSet() (*kubernetes.Clientset, error) {
    79  	clientConfig, err := f.ToRESTConfig()
    80  	if err != nil {
    81  		return nil, err
    82  	}
    83  	return kubernetes.NewForConfig(clientConfig)
    84  }
    85  
    86  func (f *factoryImpl) DynamicClient() (dynamic.Interface, error) {
    87  	clientConfig, err := f.ToRESTConfig()
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	return dynamic.NewForConfig(clientConfig)
    92  }
    93  
    94  // NewBuilder returns a new resource builder for structured api objects.
    95  func (f *factoryImpl) NewBuilder() *resource.Builder {
    96  	return resource.NewBuilder(f.clientGetter)
    97  }
    98  
    99  func (f *factoryImpl) RESTClient() (*restclient.RESTClient, error) {
   100  	clientConfig, err := f.ToRESTConfig()
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	setKubernetesDefaults(clientConfig)
   105  	return restclient.RESTClientFor(clientConfig)
   106  }
   107  
   108  func (f *factoryImpl) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
   109  	cfg, err := f.clientGetter.ToRESTConfig()
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  	if err := setKubernetesDefaults(cfg); err != nil {
   114  		return nil, err
   115  	}
   116  	gvk := mapping.GroupVersionKind
   117  	switch gvk.Group {
   118  	case corev1.GroupName:
   119  		cfg.APIPath = "/api"
   120  	default:
   121  		cfg.APIPath = "/apis"
   122  	}
   123  	gv := gvk.GroupVersion()
   124  	cfg.GroupVersion = &gv
   125  	return restclient.RESTClientFor(cfg)
   126  }
   127  
   128  func (f *factoryImpl) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) {
   129  	cfg, err := f.clientGetter.ToRESTConfig()
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	if err := restclient.SetKubernetesDefaults(cfg); err != nil {
   134  		return nil, err
   135  	}
   136  	cfg.APIPath = "/apis"
   137  	if mapping.GroupVersionKind.Group == corev1.GroupName {
   138  		cfg.APIPath = "/api"
   139  	}
   140  	gv := mapping.GroupVersionKind.GroupVersion()
   141  	cfg.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
   142  	cfg.GroupVersion = &gv
   143  	return restclient.RESTClientFor(cfg)
   144  }
   145  
   146  func (f *factoryImpl) Validator(validationDirective string) (validation.Schema, error) {
   147  	// client-side schema validation is only performed
   148  	// when the validationDirective is strict.
   149  	// If the directive is warn, we rely on the ParamVerifyingSchema
   150  	// to ignore the client-side validation and provide a warning
   151  	// to the user that attempting warn validation when SS validation
   152  	// is unsupported is inert.
   153  	if validationDirective == metav1.FieldValidationIgnore {
   154  		return validation.NullSchema{}, nil
   155  	}
   156  
   157  	schema := validation.ConjunctiveSchema{
   158  		validation.NewSchemaValidation(f),
   159  		validation.NoDoubleKeySchema{},
   160  	}
   161  
   162  	dynamicClient, err := f.DynamicClient()
   163  	if err != nil {
   164  		return nil, err
   165  	}
   166  	// Create the FieldValidationVerifier for use in the ParamVerifyingSchema.
   167  	discoveryClient, err := f.ToDiscoveryClient()
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  	// Memory-cache the OpenAPI V3 responses. The disk cache behavior is determined by
   172  	// the discovery client.
   173  	oapiV3Client := cached.NewClient(discoveryClient.OpenAPIV3())
   174  	queryParam := resource.QueryParamFieldValidation
   175  	primary := resource.NewQueryParamVerifierV3(dynamicClient, oapiV3Client, queryParam)
   176  	secondary := resource.NewQueryParamVerifier(dynamicClient, f.openAPIGetter(), queryParam)
   177  	fallback := resource.NewFallbackQueryParamVerifier(primary, secondary)
   178  	return validation.NewParamVerifyingSchema(schema, fallback, string(validationDirective)), nil
   179  }
   180  
   181  // OpenAPISchema returns metadata and structural information about
   182  // Kubernetes object definitions.
   183  func (f *factoryImpl) OpenAPISchema() (openapi.Resources, error) {
   184  	openAPIGetter := f.openAPIGetter()
   185  	if openAPIGetter == nil {
   186  		return nil, errors.New("no openapi getter")
   187  	}
   188  
   189  	// Lazily initialize the OpenAPIParser once
   190  	f.parser.Do(func() {
   191  		// Create the caching OpenAPIParser
   192  		f.openAPIParser = openapi.NewOpenAPIParser(f.openAPIGetter())
   193  	})
   194  
   195  	// Delegate to the OpenAPIPArser
   196  	return f.openAPIParser.Parse()
   197  }
   198  
   199  func (f *factoryImpl) openAPIGetter() discovery.OpenAPISchemaInterface {
   200  	discovery, err := f.clientGetter.ToDiscoveryClient()
   201  	if err != nil {
   202  		return nil
   203  	}
   204  	f.getter.Do(func() {
   205  		f.oapi = openapi.NewOpenAPIGetter(discovery)
   206  	})
   207  
   208  	return f.oapi
   209  }
   210  
   211  func (f *factoryImpl) OpenAPIV3Client() (openapiclient.Client, error) {
   212  	discovery, err := f.clientGetter.ToDiscoveryClient()
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  
   217  	return cached.NewClient(discovery.OpenAPIV3()), nil
   218  }
   219  

View as plain text