mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-15 06:01:50 +00:00
Allow server and client to take api version as argument
* Defaults to v1beta1 * apiserver takes -storage_version which controls etcd storage version and the version of the client used to connect to other apiservers * Changed signature of client.New to add version parameter * All controller code and component code prefers the oldest (most common) server version
This commit is contained in:
@@ -23,6 +23,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
@@ -96,19 +97,30 @@ type Client struct {
|
||||
// New creates a Kubernetes client. This client works with pods, replication controllers
|
||||
// and services. It allows operations such as list, get, update and delete on these objects.
|
||||
// host must be a host string, a host:port combo, or an http or https URL. Passing a prefix
|
||||
// to a URL will prepend the server path. Returns an error if host cannot be converted to a
|
||||
// valid URL.
|
||||
func New(host string, auth *AuthInfo) (*Client, error) {
|
||||
restClient, err := NewRESTClient(host, auth, "/api/v1beta1/", latest.Codec)
|
||||
// to a URL will prepend the server path. The API version to use may be specified or left
|
||||
// empty to use the client preferred version. Returns an error if host cannot be converted to
|
||||
// a valid URL.
|
||||
func New(host, version string, auth *AuthInfo) (*Client, error) {
|
||||
if version == "" {
|
||||
// Clients default to the preferred code API version
|
||||
// TODO: implement version negotation (highest version supported by server)
|
||||
version = latest.Version
|
||||
}
|
||||
serverCodec, _, err := latest.InterfacesFor(version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("API version '%s' is not recognized (valid values: %s)", version, strings.Join(latest.Versions, ", "))
|
||||
}
|
||||
prefix := fmt.Sprintf("/api/%s/", version)
|
||||
restClient, err := NewRESTClient(host, auth, prefix, serverCodec)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("API URL '%s' is not valid: %v", host, err)
|
||||
}
|
||||
return &Client{restClient}, nil
|
||||
}
|
||||
|
||||
// NewOrDie creates a Kubernetes client and panics if the provided host is invalid.
|
||||
func NewOrDie(host string, auth *AuthInfo) *Client {
|
||||
client, err := New(host, auth)
|
||||
func NewOrDie(host, version string, auth *AuthInfo) *Client {
|
||||
client, err := New(host, version, auth)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@@ -27,6 +27,8 @@ import (
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@@ -36,6 +38,38 @@ import (
|
||||
// TODO: Move this to a common place, it's needed in multiple tests.
|
||||
const apiPath = "/api/v1beta1"
|
||||
|
||||
func TestChecksCodec(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
Err bool
|
||||
Prefix string
|
||||
Codec runtime.Codec
|
||||
}{
|
||||
"v1beta1": {false, "/api/v1beta1/", v1beta1.Codec},
|
||||
"": {false, "/api/v1beta1/", v1beta1.Codec},
|
||||
"v1beta2": {false, "/api/v1beta2/", v1beta2.Codec},
|
||||
"v1beta3": {true, "", nil},
|
||||
}
|
||||
for version, expected := range testCases {
|
||||
client, err := New("127.0.0.1", version, nil)
|
||||
switch {
|
||||
case err == nil && expected.Err:
|
||||
t.Errorf("expected error but was nil")
|
||||
continue
|
||||
case err != nil && !expected.Err:
|
||||
t.Errorf("unexpected error %v", err)
|
||||
continue
|
||||
case err != nil:
|
||||
continue
|
||||
}
|
||||
if e, a := expected.Prefix, client.prefix; e != a {
|
||||
t.Errorf("expected %#v, got %#v", e, a)
|
||||
}
|
||||
if e, a := expected.Codec, client.Codec; e != a {
|
||||
t.Errorf("expected %#v, got %#v", e, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidatesHostParameter(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
Host string
|
||||
@@ -49,7 +83,7 @@ func TestValidatesHostParameter(t *testing.T) {
|
||||
"host/server": {"", "", true},
|
||||
}
|
||||
for k, expected := range testCases {
|
||||
c, err := NewRESTClient(k, nil, "/api/v1beta1/", latest.Codec)
|
||||
c, err := NewRESTClient(k, nil, "/api/v1beta1/", v1beta1.Codec)
|
||||
switch {
|
||||
case err == nil && expected.Err:
|
||||
t.Errorf("expected error but was nil")
|
||||
@@ -355,7 +389,7 @@ func (c *testClient) Setup() *testClient {
|
||||
}
|
||||
c.server = httptest.NewServer(c.handler)
|
||||
if c.Client == nil {
|
||||
c.Client = NewOrDie("localhost", nil)
|
||||
c.Client = NewOrDie("localhost", "v1beta1", nil)
|
||||
}
|
||||
c.Client.host = c.server.URL
|
||||
c.Client.prefix = "/api/v1beta1/"
|
||||
@@ -512,7 +546,7 @@ func TestDoRequest(t *testing.T) {
|
||||
testClients := []testClient{
|
||||
{Request: testRequest{Method: "GET", Path: "good"}, Response: Response{StatusCode: 200}},
|
||||
{Request: testRequest{Method: "GET", Path: "bad%ZZ"}, Error: true},
|
||||
{Client: NewOrDie("localhost", &AuthInfo{"foo", "bar"}), Request: testRequest{Method: "GET", Path: "auth", Header: "Authorization"}, Response: Response{StatusCode: 200}},
|
||||
{Client: NewOrDie("localhost", "v1beta1", &AuthInfo{"foo", "bar"}), Request: testRequest{Method: "GET", Path: "auth", Header: "Authorization"}, Response: Response{StatusCode: 200}},
|
||||
{Client: &Client{&RESTClient{httpClient: http.DefaultClient}}, Request: testRequest{Method: "GET", Path: "nocertificate"}, Error: true},
|
||||
{Request: testRequest{Method: "GET", Path: "error"}, Response: Response{StatusCode: 500}, Error: true},
|
||||
{Request: testRequest{Method: "POST", Path: "faildecode"}, Response: Response{StatusCode: 200, RawBody: &invalid}},
|
||||
@@ -543,7 +577,7 @@ func TestDoRequestAccepted(t *testing.T) {
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
request, _ := http.NewRequest("GET", testServer.URL+"/foo/bar", nil)
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c, err := New(testServer.URL, &auth)
|
||||
c, err := New(testServer.URL, "", &auth)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -580,7 +614,7 @@ func TestDoRequestAcceptedSuccess(t *testing.T) {
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
request, _ := http.NewRequest("GET", testServer.URL+"/foo/bar", nil)
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c, err := New(testServer.URL, &auth)
|
||||
c, err := New(testServer.URL, "", &auth)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -617,7 +651,7 @@ func TestGetServerVersion(t *testing.T) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(output)
|
||||
}))
|
||||
client := NewOrDie(server.URL, nil)
|
||||
client := NewOrDie(server.URL, "", nil)
|
||||
|
||||
got, err := client.ServerVersion()
|
||||
if err != nil {
|
||||
|
@@ -29,7 +29,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta2"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
||||
@@ -39,7 +40,7 @@ import (
|
||||
func TestDoRequestNewWay(t *testing.T) {
|
||||
reqBody := "request body"
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
expectedBody, _ := v1beta2.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -47,7 +48,7 @@ func TestDoRequestNewWay(t *testing.T) {
|
||||
}
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c := NewOrDie(testServer.URL, &auth)
|
||||
c := NewOrDie(testServer.URL, "v1beta2", &auth)
|
||||
obj, err := c.Verb("POST").
|
||||
Path("foo/bar").
|
||||
Path("baz").
|
||||
@@ -64,7 +65,7 @@ func TestDoRequestNewWay(t *testing.T) {
|
||||
} else if !reflect.DeepEqual(obj, expectedObj) {
|
||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||
}
|
||||
fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz?labels=name%3Dfoo", "POST", &reqBody)
|
||||
fakeHandler.ValidateRequest(t, "/api/v1beta2/foo/bar/baz?labels=name%3Dfoo", "POST", &reqBody)
|
||||
if fakeHandler.RequestReceived.Header["Authorization"] == nil {
|
||||
t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived)
|
||||
}
|
||||
@@ -72,9 +73,9 @@ func TestDoRequestNewWay(t *testing.T) {
|
||||
|
||||
func TestDoRequestNewWayReader(t *testing.T) {
|
||||
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
reqBodyExpected, _ := latest.Codec.Encode(reqObj)
|
||||
reqBodyExpected, _ := v1beta1.Codec.Encode(reqObj)
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
expectedBody, _ := v1beta1.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -82,7 +83,7 @@ func TestDoRequestNewWayReader(t *testing.T) {
|
||||
}
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c := NewOrDie(testServer.URL, &auth)
|
||||
c := NewOrDie(testServer.URL, "v1beta1", &auth)
|
||||
obj, err := c.Verb("POST").
|
||||
Path("foo/bar").
|
||||
Path("baz").
|
||||
@@ -109,9 +110,9 @@ func TestDoRequestNewWayReader(t *testing.T) {
|
||||
|
||||
func TestDoRequestNewWayObj(t *testing.T) {
|
||||
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
reqBodyExpected, _ := latest.Codec.Encode(reqObj)
|
||||
reqBodyExpected, _ := v1beta2.Codec.Encode(reqObj)
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
expectedBody, _ := v1beta2.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -119,7 +120,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
|
||||
}
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c := NewOrDie(testServer.URL, &auth)
|
||||
c := NewOrDie(testServer.URL, "v1beta2", &auth)
|
||||
obj, err := c.Verb("POST").
|
||||
Path("foo/bar").
|
||||
Path("baz").
|
||||
@@ -137,7 +138,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
|
||||
t.Errorf("Expected: %#v, got %#v", expectedObj, obj)
|
||||
}
|
||||
tmpStr := string(reqBodyExpected)
|
||||
fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz?labels=name%3Dfoo", "POST", &tmpStr)
|
||||
fakeHandler.ValidateRequest(t, "/api/v1beta2/foo/bar/baz?labels=name%3Dfoo", "POST", &tmpStr)
|
||||
if fakeHandler.RequestReceived.Header["Authorization"] == nil {
|
||||
t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived)
|
||||
}
|
||||
@@ -145,7 +146,7 @@ func TestDoRequestNewWayObj(t *testing.T) {
|
||||
|
||||
func TestDoRequestNewWayFile(t *testing.T) {
|
||||
reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}}
|
||||
reqBodyExpected, err := latest.Codec.Encode(reqObj)
|
||||
reqBodyExpected, err := v1beta1.Codec.Encode(reqObj)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -161,7 +162,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
|
||||
}
|
||||
|
||||
expectedObj := &api.Service{Port: 12345}
|
||||
expectedBody, _ := latest.Codec.Encode(expectedObj)
|
||||
expectedBody, _ := v1beta1.Codec.Encode(expectedObj)
|
||||
fakeHandler := util.FakeHandler{
|
||||
StatusCode: 200,
|
||||
ResponseBody: string(expectedBody),
|
||||
@@ -169,7 +170,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
|
||||
}
|
||||
testServer := httptest.NewServer(&fakeHandler)
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c := NewOrDie(testServer.URL, &auth)
|
||||
c := NewOrDie(testServer.URL, "v1beta1", &auth)
|
||||
obj, err := c.Verb("POST").
|
||||
Path("foo/bar").
|
||||
Path("baz").
|
||||
@@ -194,7 +195,7 @@ func TestDoRequestNewWayFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestVerbs(t *testing.T) {
|
||||
c := NewOrDie("localhost", nil)
|
||||
c := NewOrDie("localhost", "", nil)
|
||||
if r := c.Post(); r.verb != "POST" {
|
||||
t.Errorf("Post verb is wrong")
|
||||
}
|
||||
@@ -211,7 +212,7 @@ func TestVerbs(t *testing.T) {
|
||||
|
||||
func TestAbsPath(t *testing.T) {
|
||||
expectedPath := "/bar/foo"
|
||||
c := NewOrDie("localhost", nil)
|
||||
c := NewOrDie("localhost", "", nil)
|
||||
r := c.Post().Path("/foo").AbsPath(expectedPath)
|
||||
if r.path != expectedPath {
|
||||
t.Errorf("unexpected path: %s, expected %s", r.path, expectedPath)
|
||||
@@ -219,7 +220,7 @@ func TestAbsPath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSync(t *testing.T) {
|
||||
c := NewOrDie("localhost", nil)
|
||||
c := NewOrDie("localhost", "", nil)
|
||||
r := c.Get()
|
||||
if r.sync {
|
||||
t.Errorf("sync has wrong default")
|
||||
@@ -246,7 +247,7 @@ func TestUintParam(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
c := NewOrDie("localhost", nil)
|
||||
c := NewOrDie("localhost", "", nil)
|
||||
r := c.Get().AbsPath("").UintParam(item.name, item.testVal)
|
||||
if e, a := item.expectStr, r.finalURL(); e != a {
|
||||
t.Errorf("expected %v, got %v", e, a)
|
||||
@@ -265,7 +266,7 @@ func TestUnacceptableParamNames(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, item := range table {
|
||||
c := NewOrDie("localhost", nil)
|
||||
c := NewOrDie("localhost", "", nil)
|
||||
r := c.Get().setParam(item.name, item.testVal)
|
||||
if e, a := item.expectSuccess, r.err == nil; e != a {
|
||||
t.Errorf("expected %v, got %v (%v)", e, a, r.err)
|
||||
@@ -274,7 +275,7 @@ func TestUnacceptableParamNames(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetPollPeriod(t *testing.T) {
|
||||
c := NewOrDie("localhost", nil)
|
||||
c := NewOrDie("localhost", "", nil)
|
||||
r := c.Get()
|
||||
if r.pollPeriod == 0 {
|
||||
t.Errorf("polling should be on by default")
|
||||
@@ -296,7 +297,7 @@ func TestPolling(t *testing.T) {
|
||||
|
||||
callNumber := 0
|
||||
testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
data, err := latest.Codec.Encode(objects[callNumber])
|
||||
data, err := v1beta1.Codec.Encode(objects[callNumber])
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected encode error")
|
||||
}
|
||||
@@ -305,7 +306,7 @@ func TestPolling(t *testing.T) {
|
||||
}))
|
||||
|
||||
auth := AuthInfo{User: "user", Password: "pass"}
|
||||
c := NewOrDie(testServer.URL, &auth)
|
||||
c := NewOrDie(testServer.URL, "v1beta1", &auth)
|
||||
|
||||
trials := []func(){
|
||||
func() {
|
||||
@@ -402,7 +403,7 @@ func TestWatch(t *testing.T) {
|
||||
|
||||
encoder := json.NewEncoder(w)
|
||||
for _, item := range table {
|
||||
data, err := api.NewJSONWatchEvent(latest.Codec, watch.Event{item.t, item.obj})
|
||||
data, err := api.NewJSONWatchEvent(v1beta1.Codec, watch.Event{item.t, item.obj})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -413,7 +414,7 @@ func TestWatch(t *testing.T) {
|
||||
}
|
||||
}))
|
||||
|
||||
s, err := New(testServer.URL, &auth)
|
||||
s, err := New(testServer.URL, "v1beta1", &auth)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
Reference in New Issue
Block a user