-
Notifications
You must be signed in to change notification settings - Fork 38.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
clean up client version negotiation to handle no legacy API #35799
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,8 @@ limitations under the License. | |
package util | ||
|
||
import ( | ||
"sync" | ||
|
||
fed_clientset "k8s.io/kubernetes/federation/client/clientset_generated/federation_internalclientset" | ||
"k8s.io/kubernetes/pkg/api/unversioned" | ||
"k8s.io/kubernetes/pkg/apimachinery/registered" | ||
|
@@ -43,51 +45,75 @@ type ClientCache struct { | |
clientsets map[unversioned.GroupVersion]*internalclientset.Clientset | ||
fedClientSets map[unversioned.GroupVersion]fed_clientset.Interface | ||
configs map[unversioned.GroupVersion]*restclient.Config | ||
defaultConfig *restclient.Config | ||
// TODO this is only ever read. It should be moved to initialization at some point. | ||
discoveryClient discovery.DiscoveryInterface | ||
matchVersion bool | ||
|
||
matchVersion bool | ||
|
||
defaultConfigLock sync.Mutex | ||
defaultConfig *restclient.Config | ||
discoveryClient discovery.DiscoveryInterface | ||
} | ||
|
||
// ClientConfigForVersion returns the correct config for a server | ||
func (c *ClientCache) ClientConfigForVersion(version *unversioned.GroupVersion) (*restclient.Config, error) { | ||
if c.defaultConfig == nil { | ||
config, err := c.loader.ClientConfig() | ||
if err != nil { | ||
return nil, err | ||
} | ||
c.defaultConfig = config | ||
if c.matchVersion { | ||
if err := discovery.MatchesServerVersion(c.discoveryClient, config); err != nil { | ||
return nil, err | ||
} | ||
} | ||
// also looks up the discovery client. We can't do this during init because the flags won't have been set | ||
// because this is constructed pre-command execution before the command tree is even set up | ||
func (c *ClientCache) getDefaultConfig() (restclient.Config, discovery.DiscoveryInterface, error) { | ||
c.defaultConfigLock.Lock() | ||
defer c.defaultConfigLock.Unlock() | ||
|
||
if c.defaultConfig != nil && c.discoveryClient != nil { | ||
return *c.defaultConfig, c.discoveryClient, nil | ||
} | ||
if version != nil { | ||
if config, ok := c.configs[*version]; ok { | ||
return config, nil | ||
|
||
config, err := c.loader.ClientConfig() | ||
if err != nil { | ||
return restclient.Config{}, nil, err | ||
} | ||
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config) | ||
if err != nil { | ||
return restclient.Config{}, nil, err | ||
} | ||
if c.matchVersion { | ||
if err := discovery.MatchesServerVersion(discoveryClient); err != nil { | ||
return restclient.Config{}, nil, err | ||
} | ||
} | ||
|
||
c.defaultConfig = config | ||
c.discoveryClient = discoveryClient | ||
return *c.defaultConfig, c.discoveryClient, nil | ||
} | ||
|
||
// ClientConfigForVersion returns the correct config for a server | ||
func (c *ClientCache) ClientConfigForVersion(requiredVersion *unversioned.GroupVersion) (*restclient.Config, error) { | ||
// TODO: have a better config copy method | ||
config := *c.defaultConfig | ||
config, discoveryClient, err := c.getDefaultConfig() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if requiredVersion == nil && config.GroupVersion != nil { | ||
// if someone has set the values via flags, our config will have the groupVersion set | ||
// that means it is required. | ||
requiredVersion = config.GroupVersion | ||
} | ||
|
||
// TODO these fall out when we finish the refactor | ||
var preferredGV *unversioned.GroupVersion | ||
if version != nil { | ||
versionCopy := *version | ||
preferredGV = &versionCopy | ||
// required version may still be nil, since config.GroupVersion may have been nil. Do the check | ||
// before looking up from the cache | ||
if requiredVersion != nil { | ||
if config, ok := c.configs[*requiredVersion]; ok { | ||
return config, nil | ||
} | ||
} | ||
|
||
oldclient.SetKubernetesDefaults(&config) | ||
negotiatedVersion, err := discovery.NegotiateVersion(c.discoveryClient, &config, preferredGV, registered.EnabledVersions()) | ||
negotiatedVersion, err := discovery.NegotiateVersion(discoveryClient, requiredVersion, registered.EnabledVersions()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
config.GroupVersion = negotiatedVersion | ||
|
||
if version != nil { | ||
c.configs[*version] = &config | ||
// TODO this isn't what we want. Each clientset should be setting defaults as it sees fit. | ||
oldclient.SetKubernetesDefaults(&config) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we hoist this up and out of this code? It's no longer correct in the original sense of what it was used for (there are different defaulters). It's really There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This now uses the |
||
|
||
if requiredVersion != nil { | ||
c.configs[*requiredVersion] = &config | ||
} | ||
|
||
// `version` does not necessarily equal `config.Version`. However, we know that we call this method again with | ||
|
@@ -100,13 +126,13 @@ func (c *ClientCache) ClientConfigForVersion(version *unversioned.GroupVersion) | |
|
||
// ClientSetForVersion initializes or reuses a clientset for the specified version, or returns an | ||
// error if that is not possible | ||
func (c *ClientCache) ClientSetForVersion(version *unversioned.GroupVersion) (*internalclientset.Clientset, error) { | ||
if version != nil { | ||
if clientset, ok := c.clientsets[*version]; ok { | ||
func (c *ClientCache) ClientSetForVersion(requiredVersion *unversioned.GroupVersion) (*internalclientset.Clientset, error) { | ||
if requiredVersion != nil { | ||
if clientset, ok := c.clientsets[*requiredVersion]; ok { | ||
return clientset, nil | ||
} | ||
} | ||
config, err := c.ClientConfigForVersion(version) | ||
config, err := c.ClientConfigForVersion(requiredVersion) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -120,13 +146,13 @@ func (c *ClientCache) ClientSetForVersion(version *unversioned.GroupVersion) (*i | |
// `version` does not necessarily equal `config.Version`. However, we know that if we call this method again with | ||
// `version`, we should get a client based on the same config we just found. There's no guarantee that a client | ||
// is copiable, so create a new client and save it in the cache. | ||
if version != nil { | ||
if requiredVersion != nil { | ||
configCopy := *config | ||
clientset, err := internalclientset.NewForConfig(&configCopy) | ||
if err != nil { | ||
return nil, err | ||
} | ||
c.clientsets[*version] = clientset | ||
c.clientsets[*requiredVersion] = clientset | ||
} | ||
|
||
return clientset, nil | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this up since it guards defaultConfig and discoveryClient.
matchVersion shouldn't be in this block since it isn't written under the lock.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done