Merge pull request #3269 from smarterclayton/fix_legacy_support

Make RESTClient more generic to API version, simplify version handling
This commit is contained in:
Daniel Smith 2015-01-07 15:24:02 -08:00
commit 3e0b4cfabc
13 changed files with 233 additions and 88 deletions

View File

@ -44,7 +44,7 @@ func (c *Client) ReplicationControllers(namespace string) ReplicationControllerI
}
func (c *Client) Nodes() NodeInterface {
return newNodes(c, c.preV1Beta3)
return newNodes(c)
}
func (c *Client) Events(namespace string) EventInterface {
@ -78,9 +78,6 @@ type APIStatus interface {
// Client is the implementation of a Kubernetes client.
type Client struct {
*RESTClient
// preV1Beta3 is true for v1beta1 and v1beta2
preV1Beta3 bool
}
// ServerVersion retrieves and parses the server's version.
@ -132,3 +129,8 @@ func IsTimeout(err error) bool {
}
return false
}
// preV1Beta3 returns true if the provided API version is an API introduced before v1beta3.
func preV1Beta3(version string) bool {
return version == "v1beta1" || version == "v1beta2"
}

View File

@ -165,7 +165,7 @@ func (c *testClient) ValidateCommon(t *testing.T, err error) {
// buildResourcePath is a convenience function for knowing if a namespace should be in a path param or not
func buildResourcePath(namespace, resource string) string {
if len(namespace) > 0 {
if NamespaceInPathFor(testapi.Version()) {
if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") {
return path.Join("ns", namespace, resource)
}
}
@ -183,7 +183,7 @@ func buildQueryValues(namespace string, query url.Values) url.Values {
}
}
if len(namespace) > 0 {
if !NamespaceInPathFor(testapi.Version()) {
if testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2" {
v.Set("namespace", namespace)
}
}
@ -765,7 +765,7 @@ func TestNewMinionPath(t *testing.T) {
Response: Response{StatusCode: 200},
}
cl := c.Setup()
cl.preV1Beta3 = false
cl.apiVersion = "v1beta3"
err := cl.Nodes().Delete("foo")
c.Validate(t, nil, err)
}

View File

@ -90,23 +90,28 @@ func (f HTTPClientFunc) Do(req *http.Request) (*http.Response, error) {
type FakeRESTClient struct {
Client HTTPClient
Codec runtime.Codec
Legacy bool
Req *http.Request
Resp *http.Response
Err error
}
func (c *FakeRESTClient) Get() *Request {
return NewRequest(c, "GET", &url.URL{Host: "localhost"}, c.Codec, true)
return NewRequest(c, "GET", &url.URL{Host: "localhost"}, c.Codec, c.Legacy, c.Legacy)
}
func (c *FakeRESTClient) Put() *Request {
return NewRequest(c, "PUT", &url.URL{Host: "localhost"}, c.Codec, true)
return NewRequest(c, "PUT", &url.URL{Host: "localhost"}, c.Codec, c.Legacy, c.Legacy)
}
func (c *FakeRESTClient) Post() *Request {
return NewRequest(c, "POST", &url.URL{Host: "localhost"}, c.Codec, true)
return NewRequest(c, "POST", &url.URL{Host: "localhost"}, c.Codec, c.Legacy, c.Legacy)
}
func (c *FakeRESTClient) Delete() *Request {
return NewRequest(c, "DELETE", &url.URL{Host: "localhost"}, c.Codec, true)
return NewRequest(c, "DELETE", &url.URL{Host: "localhost"}, c.Codec, c.Legacy, c.Legacy)
}
func (c *FakeRESTClient) Do(req *http.Request) (*http.Response, error) {
c.Req = req
if c.Client != HTTPClient(nil) {

View File

@ -24,6 +24,7 @@ import (
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/latest"
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
)
// Config holds the common attributes that can be passed to a Kubernetes client on
@ -34,9 +35,19 @@ type Config struct {
// Prefix is the sub path of the server. If not specified, the client will set
// a default value. Use "/" to indicate the server root should be used
Prefix string
// Version is the API version to talk to. If not specified, the client will use
// the preferred version.
// Version is the API version to talk to. Must be provided when initializing
// a RESTClient directly. When initializing a Client, will be set with the default
// code version.
Version string
// LegacyBehavior defines whether the RESTClient should follow conventions that
// existed prior to v1beta3 in Kubernetes - namely, namespace (if specified)
// not being part of the path, and resource names allowing mixed case. Set to
// true when using Kubernetes v1beta1 or v1beta2.
LegacyBehavior bool
// Codec specifies the encoding and decoding behavior for runtime.Objects passed
// to a RESTClient or Client. Required when initializing a RESTClient, optional
// when initializing a Client.
Codec runtime.Codec
// Server requires Basic authentication
Username string
@ -80,16 +91,14 @@ type KubeletConfig struct {
// is not valid.
func New(c *Config) (*Client, error) {
config := *c
if config.Prefix == "" {
config.Prefix = "/api"
if err := SetKubernetesDefaults(&config); err != nil {
return nil, err
}
client, err := RESTClientFor(&config)
if err != nil {
return nil, err
}
version := defaultVersionFor(&config)
isPreV1Beta3 := (version == "v1beta1" || version == "v1beta2")
return &Client{client, isPreV1Beta3}, nil
return &Client{client}, nil
}
// NewOrDie creates a Kubernetes client and panics if the provided API version is not recognized.
@ -101,15 +110,37 @@ func NewOrDie(c *Config) *Client {
return client
}
// RESTClientFor returns a RESTClient that satisfies the requested attributes on a client Config
// object.
func RESTClientFor(config *Config) (*RESTClient, error) {
version := defaultVersionFor(config)
// Set version
// SetKubernetesDefaults sets default values on the provided client config for accessing the
// Kubernetes API or returns an error if any of the defaults are impossible or invalid.
func SetKubernetesDefaults(config *Config) error {
if config.Prefix == "" {
config.Prefix = "/api"
}
if len(config.Version) == 0 {
config.Version = defaultVersionFor(config)
}
version := config.Version
versionInterfaces, err := latest.InterfacesFor(version)
if err != nil {
return nil, fmt.Errorf("API version '%s' is not recognized (valid values: %s)", version, strings.Join(latest.Versions, ", "))
return fmt.Errorf("API version '%s' is not recognized (valid values: %s)", version, strings.Join(latest.Versions, ", "))
}
if config.Codec == nil {
config.Codec = versionInterfaces.Codec
}
config.LegacyBehavior = (version == "v1beta1" || version == "v1beta2")
return nil
}
// RESTClientFor returns a RESTClient that satisfies the requested attributes on a client Config
// object. Note that a RESTClient may require fields that are optional when initializing a Client.
// A RESTClient created by this method is generic - it expects to operate on an API that follows
// the Kubernetes conventions, but may not be the Kubernetes API.
func RESTClientFor(config *Config) (*RESTClient, error) {
if len(config.Version) == 0 {
return nil, fmt.Errorf("version is required when initializing a RESTClient")
}
if config.Codec == nil {
return nil, fmt.Errorf("Codec is required when initializing a RESTClient")
}
baseURL, err := defaultServerUrlFor(config)
@ -117,7 +148,7 @@ func RESTClientFor(config *Config) (*RESTClient, error) {
return nil, err
}
client := NewRESTClient(baseURL, versionInterfaces.Codec, NamespaceInPathFor(version))
client := NewRESTClient(baseURL, config.Version, config.Codec, config.LegacyBehavior)
transport, err := TransportFor(config)
if err != nil {
@ -229,9 +260,9 @@ func IsConfigTransportTLS(config *Config) bool {
return baseURL.Scheme == "https"
}
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor
// defaultServerUrlFor is shared between IsConfigTransportTLS and RESTClientFor. It
// requires Host and Version to be set prior to being called.
func defaultServerUrlFor(config *Config) (*url.URL, error) {
version := defaultVersionFor(config)
// TODO: move the default to secure when the apiserver supports TLS by default
// config.Insecure is taken to mean "I want HTTPS but don't bother checking the certs against a CA."
defaultTLS := config.CertFile != "" || config.Insecure
@ -239,7 +270,7 @@ func defaultServerUrlFor(config *Config) (*url.URL, error) {
if host == "" {
host = "localhost"
}
return DefaultServerURL(host, config.Prefix, version, defaultTLS)
return DefaultServerURL(host, config.Prefix, config.Version, defaultTLS)
}
// defaultVersionFor is shared between defaultServerUrlFor and RESTClientFor
@ -252,9 +283,3 @@ func defaultVersionFor(config *Config) string {
}
return version
}
// namespaceInPathFor is used to control what api version should use namespace in url paths
func NamespaceInPathFor(version string) bool {
// we use query param for v1beta1/v1beta2, v1beta3+ will use path param
return (version != "v1beta1" && version != "v1beta2")
}

View File

@ -85,6 +85,10 @@ func TestIsConfigTransportTLS(t *testing.T) {
},
}
for _, testCase := range testCases {
if err := SetKubernetesDefaults(testCase.Config); err != nil {
t.Errorf("setting defaults failed for %#v: %v", testCase.Config, err)
continue
}
useTLS := IsConfigTransportTLS(testCase.Config)
if testCase.TransportTLS != useTLS {
t.Errorf("expected %v for %#v", testCase.TransportTLS, testCase.Config)

View File

@ -35,18 +35,17 @@ type NodeInterface interface {
// nodes implements NodesInterface
type nodes struct {
r *Client
preV1Beta3 bool
r *Client
}
// newNodes returns a nodes object. Uses "minions" as the
// URL resource name for v1beta1 and v1beta2.
func newNodes(c *Client, isPreV1Beta3 bool) *nodes {
return &nodes{c, isPreV1Beta3}
func newNodes(c *Client) *nodes {
return &nodes{c}
}
func (c *nodes) resourceName() string {
if c.preV1Beta3 {
if preV1Beta3(c.r.APIVersion()) {
return "minions"
}
return "nodes"

View File

@ -89,8 +89,12 @@ type Request struct {
// whether to poll.
poller PollFunc
// If true, put ns/<namespace> in path; if false, add "?namespace=<namespace>" as a query parameter
namespaceInPath bool
// If true, add "?namespace=<namespace>" as a query parameter, if false put ns/<namespace> in path
// Query parameter is considered legacy behavior
namespaceInQuery bool
// If true, lowercase resource prior to inserting into a path, if false, leave it as is. Preserving
// case is considered legacy behavior.
preserveResourceCase bool
// generic components accessible via method setters
path string
@ -110,15 +114,18 @@ type Request struct {
body io.Reader
}
// NewRequest creates a new request with the core attributes.
func NewRequest(client HTTPClient, verb string, baseURL *url.URL, codec runtime.Codec, namespaceInPath bool) *Request {
// NewRequest creates a new request helper object for accessing runtime.Objects on a server.
func NewRequest(client HTTPClient, verb string, baseURL *url.URL,
codec runtime.Codec, namespaceInQuery bool, preserveResourceCase bool) *Request {
return &Request{
client: client,
verb: verb,
baseURL: baseURL,
codec: codec,
namespaceInPath: namespaceInPath,
path: baseURL.Path,
client: client,
verb: verb,
baseURL: baseURL,
path: baseURL.Path,
codec: codec,
namespaceInQuery: namespaceInQuery,
preserveResourceCase: preserveResourceCase,
}
}
@ -323,11 +330,15 @@ func (r *Request) Poller(poller PollFunc) *Request {
func (r *Request) finalURL() string {
p := r.path
if r.namespaceInPath {
if !r.namespaceInQuery {
p = path.Join(p, "ns", r.namespace)
}
if len(r.resource) != 0 {
p = path.Join(p, r.resource)
resource := r.resource
if !r.preserveResourceCase {
resource = strings.ToLower(resource)
}
p = path.Join(p, resource)
}
// Join trims trailing slashes, so preserve r.path's trailing slash for backwards compat if nothing was changed
if len(r.resourceName) != 0 || len(r.subpath) != 0 {
@ -342,7 +353,7 @@ func (r *Request) finalURL() string {
query.Add(key, value)
}
if !r.namespaceInPath && len(r.namespace) > 0 {
if r.namespaceInQuery && len(r.namespace) > 0 {
query.Add("namespace", r.namespace)
}

View File

@ -75,21 +75,21 @@ func TestRequestWithErrorWontChange(t *testing.T) {
}
func TestRequestPreservesBaseTrailingSlash(t *testing.T) {
r := &Request{baseURL: &url.URL{}, path: "/path/"}
r := &Request{baseURL: &url.URL{}, path: "/path/", namespaceInQuery: true}
if s := r.finalURL(); s != "/path/" {
t.Errorf("trailing slash should be preserved: %s", s)
}
}
func TestRequestAbsPathPreservesTrailingSlash(t *testing.T) {
r := (&Request{baseURL: &url.URL{}}).AbsPath("/foo/")
r := (&Request{baseURL: &url.URL{}, namespaceInQuery: true}).AbsPath("/foo/")
if s := r.finalURL(); s != "/foo/" {
t.Errorf("trailing slash should be preserved: %s", s)
}
}
func TestRequestAbsPathJoins(t *testing.T) {
r := (&Request{baseURL: &url.URL{}}).AbsPath("foo/bar", "baz")
r := (&Request{baseURL: &url.URL{}, namespaceInQuery: true}).AbsPath("foo/bar", "baz")
if s := r.finalURL(); s != "foo/bar/baz" {
t.Errorf("trailing slash should be preserved: %s", s)
}
@ -100,6 +100,7 @@ func TestRequestSetsNamespace(t *testing.T) {
baseURL: &url.URL{
Path: "/",
},
namespaceInQuery: true,
}).Namespace("foo")
if r.namespace == "" {
t.Errorf("namespace should be set: %#v", r)
@ -112,7 +113,6 @@ func TestRequestSetsNamespace(t *testing.T) {
baseURL: &url.URL{
Path: "/",
},
namespaceInPath: true,
}).Namespace("foo")
if s := r.finalURL(); s != "ns/foo" {
t.Errorf("namespace should be in path: %s", s)
@ -121,9 +121,8 @@ func TestRequestSetsNamespace(t *testing.T) {
func TestRequestOrdersNamespaceInPath(t *testing.T) {
r := (&Request{
baseURL: &url.URL{},
path: "/test/",
namespaceInPath: true,
baseURL: &url.URL{},
path: "/test/",
}).Name("bar").Resource("baz").Namespace("foo")
if s := r.finalURL(); s != "/test/ns/foo/baz/bar" {
t.Errorf("namespace should be in order in path: %s", s)
@ -212,7 +211,7 @@ func TestTransformResponse(t *testing.T) {
{Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid},
}
for i, test := range testCases {
r := NewRequest(nil, "", uri, testapi.Codec(), true)
r := NewRequest(nil, "", uri, testapi.Codec(), true, true)
if test.Response.Body == nil {
test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
}

View File

@ -35,10 +35,13 @@ import (
// Most consumers should use client.New() to get a Kubernetes API client.
type RESTClient struct {
baseURL *url.URL
// A string identifying the version of the API this client is expected to use.
apiVersion string
// namespaceInPath controls if URLs should encode the namespace as path param instead of query param
// needed for backward compatibility
namespaceInPath bool
// LegacyBehavior controls if URLs should encode the namespace as a query param,
// and if resource case is preserved for supporting older API conventions of
// Kubernetes. Newer clients should leave this false.
LegacyBehavior bool
// Codec is the encoding and decoding scheme that applies to a particular set of
// REST resources.
@ -59,10 +62,9 @@ type RESTClient struct {
// NewRESTClient creates a new RESTClient. This client performs generic REST functions
// such as Get, Put, Post, and Delete on specified paths. Codec controls encoding and
// decoding of responses from the server. If the namespace should be specified as part
// of the path (after the resource), set namespaceInPath to true, otherwise it will be
// passed as "namespace" in the query string.
func NewRESTClient(baseURL *url.URL, c runtime.Codec, namespaceInPath bool) *RESTClient {
// decoding of responses from the server. If this client should use the older, legacy
// API conventions from Kubernetes API v1beta1 and v1beta2, set legacyBehavior true.
func NewRESTClient(baseURL *url.URL, apiVersion string, c runtime.Codec, legacyBehavior bool) *RESTClient {
base := *baseURL
if !strings.HasSuffix(base.Path, "/") {
base.Path += "/"
@ -71,10 +73,12 @@ func NewRESTClient(baseURL *url.URL, c runtime.Codec, namespaceInPath bool) *RES
base.Fragment = ""
return &RESTClient{
baseURL: &base,
Codec: c,
baseURL: &base,
apiVersion: apiVersion,
namespaceInPath: namespaceInPath,
Codec: c,
LegacyBehavior: legacyBehavior,
// Make asynchronous requests by default
Sync: false,
@ -106,7 +110,7 @@ func (c *RESTClient) Verb(verb string) *Request {
if poller == nil {
poller = c.DefaultPoll
}
return NewRequest(c.Client, verb, c.baseURL, c.Codec, c.namespaceInPath).Poller(poller).Sync(c.Sync).Timeout(c.Timeout)
return NewRequest(c.Client, verb, c.baseURL, c.Codec, c.LegacyBehavior, c.LegacyBehavior).Poller(poller).Sync(c.Sync).Timeout(c.Timeout)
}
// Post begins a POST request. Short for c.Verb("POST").
@ -134,6 +138,7 @@ func (c *RESTClient) Operation(name string) *Request {
return c.Get().Resource("operations").Name(name).Sync(false).NoPoll()
}
// DefaultPoll performs a polling action based on the PollPeriod set on the Client.
func (c *RESTClient) DefaultPoll(name string) (*Request, bool) {
if c.PollPeriod == 0 {
return nil, false
@ -143,3 +148,8 @@ func (c *RESTClient) DefaultPoll(name string) (*Request, bool) {
// Make a poll request
return c.Operation(name).Poller(c.DefaultPoll), true
}
// APIVersion returns the APIVersion this RESTClient is expected to use.
func (c *RESTClient) APIVersion() string {
return c.apiVersion
}

View File

@ -31,19 +31,19 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
)
func TestChecksCodec(t *testing.T) {
func TestSetsCodec(t *testing.T) {
testCases := map[string]struct {
Err bool
Prefix string
Codec runtime.Codec
}{
"v1beta1": {false, "/v1beta1/", v1beta1.Codec},
"": {false, "/v1beta1/", v1beta1.Codec},
"v1beta2": {false, "/v1beta2/", v1beta2.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 := RESTClientFor(&Config{Host: "127.0.0.1", Version: version})
client, err := New(&Config{Host: "127.0.0.1", Version: version})
switch {
case err == nil && expected.Err:
t.Errorf("expected error but was nil")
@ -54,15 +54,70 @@ func TestChecksCodec(t *testing.T) {
case err != nil:
continue
}
if e, a := expected.Prefix, client.baseURL.Path; e != a {
if e, a := expected.Prefix, client.RESTClient.baseURL.Path; e != a {
t.Errorf("expected %#v, got %#v", e, a)
}
if e, a := expected.Codec, client.Codec; e != a {
if e, a := expected.Codec, client.RESTClient.Codec; e != a {
t.Errorf("expected %#v, got %#v", e, a)
}
}
}
func TestSetDefaults(t *testing.T) {
testCases := []struct {
Config Config
After Config
Err bool
}{
{
Config{},
Config{
Prefix: "/api",
Version: latest.Version,
Codec: latest.Codec,
LegacyBehavior: (latest.Version == "v1beta1" || latest.Version == "v1beta2"),
},
false,
},
{
Config{
Version: "not_an_api",
},
Config{},
true,
},
}
for _, testCase := range testCases {
val := &testCase.Config
err := SetKubernetesDefaults(val)
switch {
case err == nil && testCase.Err:
t.Errorf("expected error but was nil")
continue
case err != nil && !testCase.Err:
t.Errorf("unexpected error %v", err)
continue
case err != nil:
continue
}
if *val != testCase.After {
t.Errorf("unexpected result object: %#v", val)
}
}
}
func TestRESTClientRequires(t *testing.T) {
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: "", Codec: testapi.Codec()}); err == nil {
t.Errorf("unexpected non-error")
}
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: "v1beta1"}); err == nil {
t.Errorf("unexpected non-error")
}
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", Version: testapi.Version(), Codec: testapi.Codec()}); err != nil {
t.Errorf("unexpected error: %v", err)
}
}
func TestValidatesHostParameter(t *testing.T) {
testCases := []struct {
Host string
@ -81,7 +136,7 @@ func TestValidatesHostParameter(t *testing.T) {
{"host/server", "", "", true},
}
for i, testCase := range testCases {
c, err := RESTClientFor(&Config{Host: testCase.Host, Prefix: testCase.Prefix, Version: "v1beta1"})
c, err := RESTClientFor(&Config{Host: testCase.Host, Prefix: testCase.Prefix, Version: "v1beta1", Codec: testapi.Codec()})
switch {
case err == nil && testCase.Err:
t.Errorf("expected error but was nil")
@ -110,7 +165,14 @@ func TestDoRequestBearer(t *testing.T) {
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
request, _ := http.NewRequest("GET", testServer.URL, nil)
c, err := RESTClientFor(&Config{Host: testServer.URL, BearerToken: "test"})
c, err := RESTClientFor(&Config{
Host: testServer.URL,
Version: testapi.Version(),
Codec: testapi.Codec(),
LegacyBehavior: true,
BearerToken: "test",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -133,7 +195,14 @@ func TestDoRequestAccepted(t *testing.T) {
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
c, err := RESTClientFor(&Config{Host: testServer.URL, Username: "test", Version: testapi.Version()})
c, err := RESTClientFor(&Config{
Host: testServer.URL,
Version: testapi.Version(),
Codec: testapi.Codec(),
LegacyBehavior: true,
Username: "test",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -167,7 +236,15 @@ func TestDoRequestAcceptedSuccess(t *testing.T) {
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
c, err := RESTClientFor(&Config{Host: testServer.URL, Username: "user", Password: "pass", Version: testapi.Version()})
c, err := RESTClientFor(&Config{
Host: testServer.URL,
Version: testapi.Version(),
Codec: testapi.Codec(),
LegacyBehavior: true,
Username: "user",
Password: "pass",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -198,7 +275,12 @@ func TestDoRequestFailed(t *testing.T) {
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
c, err := RESTClientFor(&Config{Host: testServer.URL})
c, err := RESTClientFor(&Config{
Host: testServer.URL,
Version: testapi.Version(),
Codec: testapi.Codec(),
LegacyBehavior: true,
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@ -226,7 +308,15 @@ func TestDoRequestCreated(t *testing.T) {
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
c, err := RESTClientFor(&Config{Host: testServer.URL, Username: "user", Password: "pass", Version: testapi.Version()})
c, err := RESTClientFor(&Config{
Host: testServer.URL,
Version: testapi.Version(),
Codec: testapi.Codec(),
LegacyBehavior: true,
Username: "user",
Password: "pass",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

View File

@ -48,7 +48,7 @@ func getFakeClient(t *testing.T, validURLs []string) (ClientPosterFunc, *httptes
return func(mapping *meta.RESTMapping) (RESTClientPoster, error) {
fakeCodec := runtime.CodecFor(api.Scheme, "v1beta1")
fakeUri, _ := url.Parse(server.URL + "/api/v1beta1")
return client.NewRESTClient(fakeUri, fakeCodec, false), nil
return client.NewRESTClient(fakeUri, "v1beta1", fakeCodec, true), nil
}, server
}

View File

@ -38,7 +38,7 @@ import (
)
func makeNamespaceURL(namespace, suffix string) string {
if client.NamespaceInPathFor(testapi.Version()) {
if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") {
return makeURL("/ns/" + namespace + suffix)
}
return makeURL(suffix + "?namespace=" + namespace)

View File

@ -88,7 +88,7 @@ func TestPollMinions(t *testing.T) {
}
func makeNamespaceURL(namespace, suffix string, isClient bool) string {
if client.NamespaceInPathFor(testapi.Version()) {
if !(testapi.Version() == "v1beta1" || testapi.Version() == "v1beta2") {
return makeURL("/ns/" + namespace + suffix)
}
// if this is a url the client should call, encode the url