mirror of
https://github.com/optim-enterprises-bv/kubernetes.git
synced 2025-11-03 11:48:15 +00:00
clean up client version negotiation to handle no legacy API
This commit is contained in:
@@ -20,7 +20,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/kubernetes/pkg/api/unversioned"
|
||||
"k8s.io/kubernetes/pkg/client/restclient"
|
||||
"k8s.io/kubernetes/pkg/util/sets"
|
||||
"k8s.io/kubernetes/pkg/version"
|
||||
// Import solely to initialize client auth plugins.
|
||||
@@ -30,14 +29,7 @@ import (
|
||||
// MatchesServerVersion queries the server to compares the build version
|
||||
// (git hash) of the client with the server's build version. It returns an error
|
||||
// if it failed to contact the server or if the versions are not an exact match.
|
||||
func MatchesServerVersion(client DiscoveryInterface, c *restclient.Config) error {
|
||||
var err error
|
||||
if client == nil {
|
||||
client, err = NewDiscoveryClientForConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
func MatchesServerVersion(client DiscoveryInterface) error {
|
||||
cVer := version.Get()
|
||||
sVer, err := client.ServerVersion()
|
||||
if err != nil {
|
||||
@@ -55,19 +47,9 @@ func MatchesServerVersion(client DiscoveryInterface, c *restclient.Config) error
|
||||
// a version that both client and server support.
|
||||
// - If no version is provided, try registered client versions in order of
|
||||
// preference.
|
||||
// - If version is provided, but not default config (explicitly requested via
|
||||
// commandline flag), and is unsupported by the server, print a warning to
|
||||
// stderr and try client's registered versions in order of preference.
|
||||
// - If version is config default, and the server does not support it,
|
||||
// - If version is provided and the server does not support it,
|
||||
// return an error.
|
||||
func NegotiateVersion(client DiscoveryInterface, c *restclient.Config, requestedGV *unversioned.GroupVersion, clientRegisteredGVs []unversioned.GroupVersion) (*unversioned.GroupVersion, error) {
|
||||
var err error
|
||||
if client == nil {
|
||||
client, err = NewDiscoveryClientForConfig(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
func NegotiateVersion(client DiscoveryInterface, requiredGV *unversioned.GroupVersion, clientRegisteredGVs []unversioned.GroupVersion) (*unversioned.GroupVersion, error) {
|
||||
clientVersions := sets.String{}
|
||||
for _, gv := range clientRegisteredGVs {
|
||||
clientVersions.Insert(gv.String())
|
||||
@@ -84,37 +66,23 @@ func NegotiateVersion(client DiscoveryInterface, c *restclient.Config, requested
|
||||
serverVersions.Insert(v)
|
||||
}
|
||||
|
||||
// If no version requested, use config version (may also be empty).
|
||||
// make a copy of the original so we don't risk mutating input here or in the returned value
|
||||
var preferredGV *unversioned.GroupVersion
|
||||
switch {
|
||||
case requestedGV != nil:
|
||||
t := *requestedGV
|
||||
preferredGV = &t
|
||||
case c.GroupVersion != nil:
|
||||
t := *c.GroupVersion
|
||||
preferredGV = &t
|
||||
}
|
||||
|
||||
// If version explicitly requested verify that both client and server support it.
|
||||
// If server does not support warn, but try to negotiate a lower version.
|
||||
if preferredGV != nil {
|
||||
if !clientVersions.Has(preferredGV.String()) {
|
||||
return nil, fmt.Errorf("client does not support API version %q; client supported API versions: %v", preferredGV, clientVersions)
|
||||
if requiredGV != nil {
|
||||
if !clientVersions.Has(requiredGV.String()) {
|
||||
return nil, fmt.Errorf("client does not support API version %q; client supported API versions: %v", requiredGV, clientVersions)
|
||||
|
||||
}
|
||||
// If the server supports no versions, then we should just use the preferredGV
|
||||
// This can happen because discovery fails due to 403 Forbidden errors
|
||||
if len(serverVersions) == 0 {
|
||||
return preferredGV, nil
|
||||
return requiredGV, nil
|
||||
}
|
||||
if serverVersions.Has(preferredGV.String()) {
|
||||
return preferredGV, nil
|
||||
if serverVersions.Has(requiredGV.String()) {
|
||||
return requiredGV, nil
|
||||
}
|
||||
// If we are using an explicit config version the server does not support, fail.
|
||||
if (c.GroupVersion != nil) && (*preferredGV == *c.GroupVersion) {
|
||||
return nil, fmt.Errorf("server does not support API version %q", preferredGV)
|
||||
}
|
||||
return nil, fmt.Errorf("server does not support API version %q", requiredGV)
|
||||
}
|
||||
|
||||
for _, clientGV := range clientRegisteredGVs {
|
||||
@@ -130,6 +98,12 @@ func NegotiateVersion(client DiscoveryInterface, c *restclient.Config, requested
|
||||
return &t, nil
|
||||
}
|
||||
}
|
||||
|
||||
// if we have no server versions and we have no required version, choose the first clientRegisteredVersion
|
||||
if len(serverVersions) == 0 && len(clientRegisteredGVs) > 0 {
|
||||
return &clientRegisteredGVs[0], nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("failed to negotiate an api version; server supports: %v, client supports: %v",
|
||||
serverVersions, clientVersions)
|
||||
}
|
||||
|
||||
@@ -47,19 +47,16 @@ func objBody(object interface{}) io.ReadCloser {
|
||||
func TestNegotiateVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
version *uapi.GroupVersion
|
||||
requiredVersion *uapi.GroupVersion
|
||||
expectedVersion *uapi.GroupVersion
|
||||
serverVersions []string
|
||||
clientVersions []uapi.GroupVersion
|
||||
config *restclient.Config
|
||||
expectErr func(err error) bool
|
||||
sendErr error
|
||||
statusCode int
|
||||
}{
|
||||
{
|
||||
name: "server supports client default",
|
||||
version: &uapi.GroupVersion{Version: "version1"},
|
||||
config: &restclient.Config{},
|
||||
serverVersions: []string{"version1", registered.GroupOrDie(api.GroupName).GroupVersion.String()},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &uapi.GroupVersion{Version: "version1"},
|
||||
@@ -67,8 +64,6 @@ func TestNegotiateVersion(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "server falls back to client supported",
|
||||
version: ®istered.GroupOrDie(api.GroupName).GroupVersion,
|
||||
config: &restclient.Config{},
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &uapi.GroupVersion{Version: "version1"},
|
||||
@@ -76,23 +71,30 @@ func TestNegotiateVersion(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "explicit version supported",
|
||||
config: &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}},
|
||||
requiredVersion: &uapi.GroupVersion{Version: "v1"},
|
||||
serverVersions: []string{"/version1", registered.GroupOrDie(api.GroupName).GroupVersion.String()},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion,
|
||||
expectedVersion: &uapi.GroupVersion{Version: "v1"},
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "explicit version not supported",
|
||||
config: &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}},
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), `server does not support API version "v1"`) },
|
||||
statusCode: http.StatusOK,
|
||||
name: "explicit version not supported on server",
|
||||
requiredVersion: &uapi.GroupVersion{Version: "v1"},
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), `server does not support API version "v1"`) },
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "explicit version not supported on client",
|
||||
requiredVersion: &uapi.GroupVersion{Version: "v1"},
|
||||
serverVersions: []string{"v1"},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}},
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), `client does not support API version "v1"`) },
|
||||
statusCode: http.StatusOK,
|
||||
},
|
||||
{
|
||||
name: "connection refused error",
|
||||
config: &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}},
|
||||
serverVersions: []string{"version1"},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
sendErr: errors.New("connection refused"),
|
||||
@@ -101,25 +103,21 @@ func TestNegotiateVersion(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "discovery fails due to 403 Forbidden errors and thus serverVersions is empty, use default GroupVersion",
|
||||
config: &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion,
|
||||
expectedVersion: &uapi.GroupVersion{Version: "version1"},
|
||||
statusCode: http.StatusForbidden,
|
||||
},
|
||||
{
|
||||
name: "discovery fails due to 404 Not Found errors and thus serverVersions is empty, use requested GroupVersion",
|
||||
version: &uapi.GroupVersion{Version: "version1"},
|
||||
config: &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}},
|
||||
requiredVersion: &uapi.GroupVersion{Version: "version1"},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectedVersion: &uapi.GroupVersion{Version: "version1"},
|
||||
statusCode: http.StatusNotFound,
|
||||
},
|
||||
{
|
||||
name: "discovery fails due to 403 Forbidden errors and thus serverVersions is empty, no fallback GroupVersion",
|
||||
config: &restclient.Config{},
|
||||
clientVersions: []uapi.GroupVersion{{Version: "version1"}, registered.GroupOrDie(api.GroupName).GroupVersion},
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), "failed to negotiate an api version;") },
|
||||
statusCode: http.StatusForbidden,
|
||||
name: "discovery fails due to 403 Forbidden errors and thus serverVersions is empty, no fallback GroupVersion",
|
||||
expectErr: func(err error) bool { return strings.Contains(err.Error(), "failed to negotiate an api version;") },
|
||||
statusCode: http.StatusForbidden,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -139,9 +137,9 @@ func TestNegotiateVersion(t *testing.T) {
|
||||
return &http.Response{StatusCode: test.statusCode, Header: header, Body: objBody(&uapi.APIVersions{Versions: test.serverVersions})}, nil
|
||||
}),
|
||||
}
|
||||
c := discovery.NewDiscoveryClientForConfigOrDie(test.config)
|
||||
c := discovery.NewDiscoveryClientForConfigOrDie(&restclient.Config{})
|
||||
c.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
|
||||
response, err := discovery.NegotiateVersion(c, test.config, test.version, test.clientVersions)
|
||||
response, err := discovery.NegotiateVersion(c, test.requiredVersion, test.clientVersions)
|
||||
if err == nil && test.expectErr != nil {
|
||||
t.Errorf("expected error, got nil for [%s].", test.name)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user