Commit 080d6a4b authored by David Eads's avatar David Eads

wrap restclientgetter with match version option

parent 1f535703
......@@ -276,11 +276,12 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
kubeConfigFlags := cmdutil.NewConfigFlags()
kubeConfigFlags.AddFlags(cmds.PersistentFlags())
matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
matchVersionKubeConfigFlags.AddFlags(cmds.PersistentFlags())
cmds.PersistentFlags().AddGoFlagSet(flag.CommandLine)
f := cmdutil.NewFactory(kubeConfigFlags)
f.BindFlags(cmds.PersistentFlags())
f := cmdutil.NewFactory(matchVersionKubeConfigFlags)
// Sending in 'nil' for the getLanguageFn() results in using
// the LANG environment variable.
......
......@@ -11,6 +11,7 @@ go_library(
"factory_client_access.go",
"factory_object_mapping.go",
"helpers.go",
"kubectl_match_version.go",
"printing.go",
],
importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/util",
......
......@@ -53,6 +53,7 @@ const (
flagUsername = "username"
flagPassword = "password"
flagTimeout = "request-timeout"
flagHTTPCacheDir = "cache-dir"
)
// TODO(juanvallejo): move to pkg/kubectl/genericclioptions once
......@@ -225,7 +226,7 @@ func (f *ConfigFlags) AddFlags(flags *pflag.FlagSet) {
flags.StringVar(f.KubeConfig, "kubeconfig", *f.KubeConfig, "Path to the kubeconfig file to use for CLI requests.")
}
if f.CacheDir != nil {
flags.StringVar(f.CacheDir, FlagHTTPCacheDir, *f.CacheDir, "Default HTTP cache directory")
flags.StringVar(f.CacheDir, flagHTTPCacheDir, *f.CacheDir, "Default HTTP cache directory")
}
// add config options
......
......@@ -50,14 +50,6 @@ import (
"k8s.io/kubernetes/pkg/printers"
)
const (
FlagMatchBinaryVersion = "match-server-version"
)
var (
FlagHTTPCacheDir = "cache-dir"
)
// Factory provides abstractions that allow the Kubectl command to be extended across multiple types
// of resources and different API sets.
// The rings are here for a reason. In order for composers to be able to provide alternative factory implementations
......@@ -132,9 +124,6 @@ type ClientAccessFactory interface {
// using the factory.
Command(cmd *cobra.Command, showSecrets bool) string
// BindFlags adds any flags that are common to all kubectl sub commands.
BindFlags(flags *pflag.FlagSet)
// SuggestedPodTemplateResources returns a list of resource types that declare a pod template
SuggestedPodTemplateResources() []schema.GroupResource
......
......@@ -26,7 +26,6 @@ import (
"path/filepath"
"regexp"
"strings"
"sync"
"k8s.io/api/core/v1"
......@@ -58,7 +57,6 @@ import (
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
"k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/version"
)
type RESTClientGetter interface {
......@@ -70,10 +68,6 @@ type RESTClientGetter interface {
type ring0Factory struct {
clientGetter RESTClientGetter
requireMatchedServerVersion bool
checkServerVersion sync.Once
matchesServerVersionErr error
}
func NewClientAccessFactory(clientGetter RESTClientGetter) ClientAccessFactory {
......@@ -88,6 +82,18 @@ func NewClientAccessFactory(clientGetter RESTClientGetter) ClientAccessFactory {
return f
}
func (f *ring0Factory) ClientConfig() (*restclient.Config, error) {
return f.clientGetter.ToRESTConfig()
}
func (f *ring0Factory) RESTMapper() (meta.RESTMapper, error) {
return f.clientGetter.ToRESTMapper()
}
func (f *ring0Factory) BareClientConfig() (*restclient.Config, error) {
return f.clientGetter.ToRESTConfig()
}
func (f *ring0Factory) DiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
return f.clientGetter.ToDiscoveryClient()
}
......@@ -115,41 +121,6 @@ func (f *ring0Factory) DynamicClient() (dynamic.DynamicInterface, error) {
}
return dynamic.NewForConfig(clientConfig)
}
func (f *ring0Factory) checkMatchingServerVersion() error {
f.checkServerVersion.Do(func() {
if !f.requireMatchedServerVersion {
return
}
discoveryClient, err := f.DiscoveryClient()
if err != nil {
f.matchesServerVersionErr = err
return
}
f.matchesServerVersionErr = discovery.MatchesServerVersion(version.Get(), discoveryClient)
})
return f.matchesServerVersionErr
}
func (f *ring0Factory) ClientConfig() (*restclient.Config, error) {
if err := f.checkMatchingServerVersion(); err != nil {
return nil, err
}
clientConfig, err := f.clientGetter.ToRESTConfig()
if err != nil {
return nil, err
}
setKubernetesDefaults(clientConfig)
return clientConfig, nil
}
func (f *ring0Factory) RESTMapper() (meta.RESTMapper, error) {
return f.clientGetter.ToRESTMapper()
}
func (f *ring0Factory) BareClientConfig() (*restclient.Config, error) {
return f.clientGetter.ToRESTConfig()
}
// NewBuilder returns a new resource builder for structured api objects.
func (f *ring0Factory) NewBuilder() *resource.Builder {
......@@ -161,6 +132,7 @@ func (f *ring0Factory) RESTClient() (*restclient.RESTClient, error) {
if err != nil {
return nil, err
}
setKubernetesDefaults(clientConfig)
return restclient.RESTClientFor(clientConfig)
}
......@@ -330,14 +302,6 @@ func (f *ring0Factory) Command(cmd *cobra.Command, showSecrets bool) string {
return base + args + flags
}
func (f *ring0Factory) BindFlags(flags *pflag.FlagSet) {
// Globally persistent flags across all subcommands.
// TODO Change flag names to consts to allow safer lookup from subcommands.
// TODO Add a verbose flag that turns on glog logging. Probably need a way
// to do that automatically for every subcommand.
flags.BoolVar(&f.requireMatchedServerVersion, FlagMatchBinaryVersion, false, "Require server version to match client version")
}
func (f *ring0Factory) SuggestedPodTemplateResources() []schema.GroupResource {
return []schema.GroupResource{
{Resource: "replicationcontroller"},
......@@ -640,19 +604,3 @@ func InternalVersionJSONEncoder() runtime.Encoder {
encoder := legacyscheme.Codecs.LegacyCodec(legacyscheme.Scheme.PrioritizedVersionsAllGroups()...)
return unstructured.JSONFallbackEncoder{Encoder: encoder}
}
// setKubernetesDefaults sets default values on the provided client config for accessing the
// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
// TODO this isn't what we want. Each clientset should be setting defaults as it sees fit.
func setKubernetesDefaults(config *restclient.Config) error {
// TODO remove this hack. This is allowing the GetOptions to be serialized.
config.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
if config.APIPath == "" {
config.APIPath = "/api"
}
if config.NegotiatedSerializer == nil {
config.NegotiatedSerializer = legacyscheme.Codecs
}
return restclient.SetKubernetesDefaults(config)
}
/*
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 util
import (
"sync"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kubernetes/pkg/api/legacyscheme"
"k8s.io/kubernetes/pkg/version"
)
const (
flagMatchBinaryVersion = "match-server-version"
)
// MatchVersionFlags is for setting the "match server version" function.
type MatchVersionFlags struct {
Delegate RESTClientGetter
RequireMatchedServerVersion bool
checkServerVersion sync.Once
matchesServerVersionErr error
}
var _ RESTClientGetter = &MatchVersionFlags{}
func (f *MatchVersionFlags) checkMatchingServerVersion() error {
f.checkServerVersion.Do(func() {
if !f.RequireMatchedServerVersion {
return
}
discoveryClient, err := f.Delegate.ToDiscoveryClient()
if err != nil {
f.matchesServerVersionErr = err
return
}
f.matchesServerVersionErr = discovery.MatchesServerVersion(version.Get(), discoveryClient)
})
return f.matchesServerVersionErr
}
// ToRESTConfig implements RESTClientGetter.
// Returns a REST client configuration based on a provided path
// to a .kubeconfig file, loading rules, and config flag overrides.
// Expects the AddFlags method to have been called.
func (f *MatchVersionFlags) ToRESTConfig() (*rest.Config, error) {
if err := f.checkMatchingServerVersion(); err != nil {
return nil, err
}
clientConfig, err := f.Delegate.ToRESTConfig()
if err != nil {
return nil, err
}
// TODO we should not have to do this. It smacks of something going wrong.
setKubernetesDefaults(clientConfig)
return clientConfig, nil
}
func (f *MatchVersionFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig {
return f.Delegate.ToRawKubeConfigLoader()
}
func (f *MatchVersionFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) {
if err := f.checkMatchingServerVersion(); err != nil {
return nil, err
}
return f.Delegate.ToDiscoveryClient()
}
// RESTMapper returns a mapper.
func (f *MatchVersionFlags) ToRESTMapper() (meta.RESTMapper, error) {
if err := f.checkMatchingServerVersion(); err != nil {
return nil, err
}
return f.Delegate.ToRESTMapper()
}
func (f *MatchVersionFlags) AddFlags(flags *pflag.FlagSet) {
flags.BoolVar(&f.RequireMatchedServerVersion, flagMatchBinaryVersion, f.RequireMatchedServerVersion, "Require server version to match client version")
}
func NewMatchVersionFlags(delegate RESTClientGetter) *MatchVersionFlags {
return &MatchVersionFlags{
Delegate: delegate,
}
}
// setKubernetesDefaults sets default values on the provided client config for accessing the
// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
// TODO this isn't what we want. Each clientset should be setting defaults as it sees fit.
func setKubernetesDefaults(config *rest.Config) error {
// TODO remove this hack. This is allowing the GetOptions to be serialized.
config.GroupVersion = &schema.GroupVersion{Group: "", Version: "v1"}
if config.APIPath == "" {
config.APIPath = "/api"
}
if config.NegotiatedSerializer == nil {
config.NegotiatedSerializer = legacyscheme.Codecs
}
return rest.SetKubernetesDefaults(config)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment