mirror of https://github.com/k3s-io/k3s
wrap restclientgetter with match version option
parent
1f5357034b
commit
080d6a4b0d
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
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)
|
||||
}
|
Loading…
Reference in New Issue