diff --git a/pkg/kubectl/cmd/util/clientcache.go b/pkg/kubectl/cmd/util/clientcache.go index e88e2df19a0..6905cc0593e 100644 --- a/pkg/kubectl/cmd/util/clientcache.go +++ b/pkg/kubectl/cmd/util/clientcache.go @@ -48,6 +48,9 @@ type ClientCache struct { fedClientSets map[schema.GroupVersion]fedclientset.Interface configs map[schema.GroupVersion]*restclient.Config + // noVersionConfig provides a cached config for the case of no required version specified + noVersionConfig *restclient.Config + matchVersion bool defaultConfigLock sync.Mutex @@ -104,8 +107,10 @@ func (c *ClientCache) ClientConfigForVersion(requiredVersion *schema.GroupVersio // before looking up from the cache if requiredVersion != nil { if config, ok := c.configs[*requiredVersion]; ok { - return config, nil + return copyConfig(config), nil } + } else if c.noVersionConfig != nil { + return copyConfig(c.noVersionConfig), nil } negotiatedVersion, err := discovery.NegotiateVersion(discoveryClient, requiredVersion, api.Registry.EnabledVersions()) @@ -118,15 +123,23 @@ func (c *ClientCache) ClientConfigForVersion(requiredVersion *schema.GroupVersio oldclient.SetKubernetesDefaults(&config) if requiredVersion != nil { - c.configs[*requiredVersion] = &config + c.configs[*requiredVersion] = copyConfig(&config) + } else { + c.noVersionConfig = copyConfig(&config) } // `version` does not necessarily equal `config.Version`. However, we know that we call this method again with // `config.Version`, we should get the config we've just built. - configCopy := config - c.configs[*config.GroupVersion] = &configCopy + c.configs[*config.GroupVersion] = copyConfig(&config) - return &config, nil + return copyConfig(&config), nil +} + +func copyConfig(in *restclient.Config) *restclient.Config { + configCopy := *in + copyGroupVersion := *configCopy.GroupVersion + configCopy.GroupVersion = ©GroupVersion + return &configCopy } // ClientSetForVersion initializes or reuses a clientset for the specified version, or returns an diff --git a/staging/src/k8s.io/client-go/discovery/helper.go b/staging/src/k8s.io/client-go/discovery/helper.go index 0222e188bb6..ac7f661041c 100644 --- a/staging/src/k8s.io/client-go/discovery/helper.go +++ b/staging/src/k8s.io/client-go/discovery/helper.go @@ -49,6 +49,9 @@ func MatchesServerVersion(clientVersion apimachineryversion.Info, client Discove // preference. // - If version is provided and the server does not support it, // return an error. +// TODO negotiation should be reserved for cases where we need a version for a given group. In those cases, it should return an ordered list of +// server preferences. From that list, a separate function can match from an ordered list of client versions. +// This is not what the function has ever done before, but it makes more logical sense. func NegotiateVersion(client DiscoveryInterface, requiredGV *schema.GroupVersion, clientRegisteredGVs []schema.GroupVersion) (*schema.GroupVersion, error) { clientVersions := sets.String{} for _, gv := range clientRegisteredGVs {