...

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

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

     1  /*
     2  Copyright 2018 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  package util
    18  
    19  import (
    20  	"sync"
    21  
    22  	"github.com/spf13/pflag"
    23  
    24  	"k8s.io/apimachinery/pkg/api/meta"
    25  	"k8s.io/apimachinery/pkg/runtime/schema"
    26  	"k8s.io/client-go/discovery"
    27  	"k8s.io/client-go/rest"
    28  	"k8s.io/client-go/tools/clientcmd"
    29  	"k8s.io/kubectl/pkg/scheme"
    30  
    31  	"k8s.io/cli-runtime/pkg/genericclioptions"
    32  	"k8s.io/component-base/version"
    33  )
    34  
    35  const (
    36  	flagMatchBinaryVersion = "match-server-version"
    37  )
    38  
    39  // MatchVersionFlags is for setting the "match server version" function.
    40  type MatchVersionFlags struct {
    41  	Delegate genericclioptions.RESTClientGetter
    42  
    43  	RequireMatchedServerVersion bool
    44  	checkServerVersion          sync.Once
    45  	matchesServerVersionErr     error
    46  }
    47  
    48  var _ genericclioptions.RESTClientGetter = &MatchVersionFlags{}
    49  
    50  func (f *MatchVersionFlags) checkMatchingServerVersion() error {
    51  	f.checkServerVersion.Do(func() {
    52  		if !f.RequireMatchedServerVersion {
    53  			return
    54  		}
    55  		discoveryClient, err := f.Delegate.ToDiscoveryClient()
    56  		if err != nil {
    57  			f.matchesServerVersionErr = err
    58  			return
    59  		}
    60  		f.matchesServerVersionErr = discovery.MatchesServerVersion(version.Get(), discoveryClient)
    61  	})
    62  
    63  	return f.matchesServerVersionErr
    64  }
    65  
    66  // ToRESTConfig implements RESTClientGetter.
    67  // Returns a REST client configuration based on a provided path
    68  // to a .kubeconfig file, loading rules, and config flag overrides.
    69  // Expects the AddFlags method to have been called.
    70  func (f *MatchVersionFlags) ToRESTConfig() (*rest.Config, error) {
    71  	if err := f.checkMatchingServerVersion(); err != nil {
    72  		return nil, err
    73  	}
    74  	clientConfig, err := f.Delegate.ToRESTConfig()
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	// TODO we should not have to do this.  It smacks of something going wrong.
    79  	setKubernetesDefaults(clientConfig)
    80  	return clientConfig, nil
    81  }
    82  
    83  func (f *MatchVersionFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
    84  	return f.Delegate.ToRawKubeConfigLoader()
    85  }
    86  
    87  func (f *MatchVersionFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
    88  	if err := f.checkMatchingServerVersion(); err != nil {
    89  		return nil, err
    90  	}
    91  	return f.Delegate.ToDiscoveryClient()
    92  }
    93  
    94  // ToRESTMapper returns a mapper.
    95  func (f *MatchVersionFlags) ToRESTMapper() (meta.RESTMapper, error) {
    96  	if err := f.checkMatchingServerVersion(); err != nil {
    97  		return nil, err
    98  	}
    99  	return f.Delegate.ToRESTMapper()
   100  }
   101  
   102  func (f *MatchVersionFlags) AddFlags(flags *pflag.FlagSet) {
   103  	flags.BoolVar(&f.RequireMatchedServerVersion, flagMatchBinaryVersion, f.RequireMatchedServerVersion, "Require server version to match client version")
   104  }
   105  
   106  func NewMatchVersionFlags(delegate genericclioptions.RESTClientGetter) *MatchVersionFlags {
   107  	return &MatchVersionFlags{
   108  		Delegate: delegate,
   109  	}
   110  }
   111  
   112  // setKubernetesDefaults sets default values on the provided client config for accessing the
   113  // Kubernetes API or returns an error if any of the defaults are impossible or invalid.
   114  // TODO this isn't what we want.  Each clientset should be setting defaults as it sees fit.
   115  func setKubernetesDefaults(config *rest.Config) error {
   116  	// TODO remove this hack.  This is allowing the GetOptions to be serialized.
   117  	config.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
   118  
   119  	if config.APIPath == "" {
   120  		config.APIPath = "/api"
   121  	}
   122  	if config.NegotiatedSerializer == nil {
   123  		// This codec factory ensures the resources are not converted. Therefore, resources
   124  		// will not be round-tripped through internal versions. Defaulting does not happen
   125  		// on the client.
   126  		config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
   127  	}
   128  	return rest.SetKubernetesDefaults(config)
   129  }
   130  

View as plain text