Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
1dd18673
Commit
1dd18673
authored
Jun 16, 2015
by
Brendan Burns
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #9762 from jlowdermilk/negotiate-api-version
kubectl negotiates api version to use based on client,server supported versions
parents
96c244ea
f3119122
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
105 additions
and
27 deletions
+105
-27
helper.go
pkg/client/helper.go
+66
-0
cmd_test.go
pkg/kubectl/cmd/cmd_test.go
+18
-16
clientcache.go
pkg/kubectl/cmd/util/clientcache.go
+20
-7
factory.go
pkg/kubectl/cmd/util/factory.go
+1
-4
No files found.
pkg/client/helper.go
View file @
1dd18673
...
@@ -30,8 +30,11 @@ import (
...
@@ -30,8 +30,11 @@ import (
"time"
"time"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/registered"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
"github.com/golang/glog"
)
)
// Config holds the common attributes that can be passed to a Kubernetes client on
// Config holds the common attributes that can be passed to a Kubernetes client on
...
@@ -138,6 +141,9 @@ func New(c *Config) (*Client, error) {
...
@@ -138,6 +141,9 @@ func New(c *Config) (*Client, error) {
return
&
Client
{
client
},
nil
return
&
Client
{
client
},
nil
}
}
// 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
(
c
*
Config
)
error
{
func
MatchesServerVersion
(
c
*
Config
)
error
{
client
,
err
:=
New
(
c
)
client
,
err
:=
New
(
c
)
if
err
!=
nil
{
if
err
!=
nil
{
...
@@ -156,6 +162,66 @@ func MatchesServerVersion(c *Config) error {
...
@@ -156,6 +162,66 @@ func MatchesServerVersion(c *Config) error {
return
nil
return
nil
}
}
// NegotiateVersion queries the server's supported api versions to find
// a version that both client and server support.
// - If no version is provided, try the client's registered 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,
// return an error.
func
NegotiateVersion
(
c
*
Config
,
version
string
)
(
string
,
error
)
{
client
,
err
:=
New
(
c
)
if
err
!=
nil
{
return
""
,
err
}
clientVersions
:=
util
.
StringSet
{}
for
_
,
v
:=
range
registered
.
RegisteredVersions
{
clientVersions
.
Insert
(
v
)
}
apiVersions
,
err
:=
client
.
ServerAPIVersions
()
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"couldn't read version from server: %v
\n
"
,
err
)
}
serverVersions
:=
util
.
StringSet
{}
for
_
,
v
:=
range
apiVersions
.
Versions
{
serverVersions
.
Insert
(
v
)
}
// If no version requested, use config version (may also be empty).
if
len
(
version
)
==
0
{
version
=
c
.
Version
}
// 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
len
(
version
)
!=
0
{
if
!
clientVersions
.
Has
(
version
)
{
return
""
,
fmt
.
Errorf
(
"Client does not support API version '%s'. Client supported API versions: %v"
,
version
,
clientVersions
)
}
if
serverVersions
.
Has
(
version
)
{
return
version
,
nil
}
// If we are using an explicit config version the server does not support, fail.
if
version
==
c
.
Version
{
return
""
,
fmt
.
Errorf
(
"Server does not support API version '%s'."
,
version
)
}
}
for
_
,
clientVersion
:=
range
registered
.
RegisteredVersions
{
if
serverVersions
.
Has
(
clientVersion
)
{
// Version was not explicitly requested in command config (--api-version).
// Ok to fall back to a supported version with a warning.
if
len
(
version
)
!=
0
{
glog
.
Warningf
(
"Server does not support API version '%s'. Falling back to '%s'."
,
version
,
clientVersion
)
}
return
clientVersion
,
nil
}
}
return
""
,
fmt
.
Errorf
(
"Failed to negotiate an api version. Server supports: %v. Client supports: %v."
,
serverVersions
,
registered
.
RegisteredVersions
)
}
// NewOrDie creates a Kubernetes client and panics if the provided API version is not recognized.
// NewOrDie creates a Kubernetes client and panics if the provided API version is not recognized.
func
NewOrDie
(
c
*
Config
)
*
Client
{
func
NewOrDie
(
c
*
Config
)
*
Client
{
client
,
err
:=
New
(
c
)
client
,
err
:=
New
(
c
)
...
...
pkg/kubectl/cmd/cmd_test.go
View file @
1dd18673
...
@@ -221,23 +221,25 @@ func stringBody(body string) io.ReadCloser {
...
@@ -221,23 +221,25 @@ func stringBody(body string) io.ReadCloser {
return
ioutil
.
NopCloser
(
bytes
.
NewReader
([]
byte
(
body
)))
return
ioutil
.
NopCloser
(
bytes
.
NewReader
([]
byte
(
body
)))
}
}
// TODO(jlowdermilk): refactor the Factory so we can test client versions properly,
// with different client/server version skew scenarios.
// Verify that resource.RESTClients constructed from a factory respect mapping.APIVersion
// Verify that resource.RESTClients constructed from a factory respect mapping.APIVersion
func
TestClientVersions
(
t
*
testing
.
T
)
{
//
func TestClientVersions(t *testing.T) {
f
:=
cmdutil
.
NewFactory
(
nil
)
//
f := cmdutil.NewFactory(nil)
//
version
:=
testapi
.
Version
()
//
version := testapi.Version()
mapping
:=
&
meta
.
RESTMapping
{
//
mapping := &meta.RESTMapping{
APIVersion
:
version
,
//
APIVersion: version,
}
//
}
c
,
err
:=
f
.
RESTClient
(
mapping
)
//
c, err := f.RESTClient(mapping)
if
err
!=
nil
{
//
if err != nil {
t
.
Errorf
(
"unexpected error: %v"
,
err
)
//
t.Errorf("unexpected error: %v", err)
}
//
}
client
:=
c
.
(
*
client
.
RESTClient
)
//
client := c.(*client.RESTClient)
if
client
.
APIVersion
()
!=
version
{
//
if client.APIVersion() != version {
t
.
Errorf
(
"unexpected Client APIVersion: %s %v"
,
client
.
APIVersion
,
client
)
//
t.Errorf("unexpected Client APIVersion: %s %v", client.APIVersion, client)
}
//
}
}
//
}
func
ExamplePrintReplicationController
()
{
func
ExamplePrintReplicationController
()
{
f
,
tf
,
codec
:=
NewAPIFactory
()
f
,
tf
,
codec
:=
NewAPIFactory
()
...
...
pkg/kubectl/cmd/util/clientcache.go
View file @
1dd18673
...
@@ -21,11 +21,20 @@ import (
...
@@ -21,11 +21,20 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
)
)
func
NewClientCache
(
loader
clientcmd
.
ClientConfig
)
*
clientCache
{
return
&
clientCache
{
clients
:
make
(
map
[
string
]
*
client
.
Client
),
configs
:
make
(
map
[
string
]
*
client
.
Config
),
loader
:
loader
,
}
}
// clientCache caches previously loaded clients for reuse, and ensures MatchServerVersion
// clientCache caches previously loaded clients for reuse, and ensures MatchServerVersion
// is invoked only once
// is invoked only once
type
clientCache
struct
{
type
clientCache
struct
{
loader
clientcmd
.
ClientConfig
loader
clientcmd
.
ClientConfig
clients
map
[
string
]
*
client
.
Client
clients
map
[
string
]
*
client
.
Client
configs
map
[
string
]
*
client
.
Config
defaultConfig
*
client
.
Config
defaultConfig
*
client
.
Config
matchVersion
bool
matchVersion
bool
}
}
...
@@ -44,12 +53,18 @@ func (c *clientCache) ClientConfigForVersion(version string) (*client.Config, er
...
@@ -44,12 +53,18 @@ func (c *clientCache) ClientConfigForVersion(version string) (*client.Config, er
}
}
}
}
}
}
if
config
,
ok
:=
c
.
configs
[
version
];
ok
{
return
config
,
nil
}
// TODO: have a better config copy method
// TODO: have a better config copy method
config
:=
*
c
.
defaultConfig
config
:=
*
c
.
defaultConfig
if
len
(
version
)
!=
0
{
negotiatedVersion
,
err
:=
client
.
NegotiateVersion
(
&
config
,
version
)
config
.
Version
=
version
if
err
!=
nil
{
return
nil
,
err
}
}
config
.
Version
=
negotiatedVersion
client
.
SetKubernetesDefaults
(
&
config
)
client
.
SetKubernetesDefaults
(
&
config
)
c
.
configs
[
version
]
=
&
config
return
&
config
,
nil
return
&
config
,
nil
}
}
...
@@ -57,15 +72,13 @@ func (c *clientCache) ClientConfigForVersion(version string) (*client.Config, er
...
@@ -57,15 +72,13 @@ func (c *clientCache) ClientConfigForVersion(version string) (*client.Config, er
// ClientForVersion initializes or reuses a client for the specified version, or returns an
// ClientForVersion initializes or reuses a client for the specified version, or returns an
// error if that is not possible
// error if that is not possible
func
(
c
*
clientCache
)
ClientForVersion
(
version
string
)
(
*
client
.
Client
,
error
)
{
func
(
c
*
clientCache
)
ClientForVersion
(
version
string
)
(
*
client
.
Client
,
error
)
{
if
client
,
ok
:=
c
.
clients
[
version
];
ok
{
return
client
,
nil
}
config
,
err
:=
c
.
ClientConfigForVersion
(
version
)
config
,
err
:=
c
.
ClientConfigForVersion
(
version
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
if
client
,
ok
:=
c
.
clients
[
config
.
Version
];
ok
{
return
client
,
nil
}
client
,
err
:=
client
.
New
(
config
)
client
,
err
:=
client
.
New
(
config
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
...
...
pkg/kubectl/cmd/util/factory.go
View file @
1dd18673
...
@@ -102,10 +102,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
...
@@ -102,10 +102,7 @@ func NewFactory(optionalClientConfig clientcmd.ClientConfig) *Factory {
clientConfig
=
DefaultClientConfig
(
flags
)
clientConfig
=
DefaultClientConfig
(
flags
)
}
}
clients
:=
&
clientCache
{
clients
:=
NewClientCache
(
clientConfig
)
clients
:
make
(
map
[
string
]
*
client
.
Client
),
loader
:
clientConfig
,
}
return
&
Factory
{
return
&
Factory
{
clients
:
clients
,
clients
:
clients
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment