Commit 36cfc02c authored by Daniel Smith's avatar Daniel Smith

Merge pull request #3066 from derekwaynecarr/client_update

Do not use namespace in url paths pre v1beta3 from client
parents 3672f93a abb6632d
...@@ -96,16 +96,16 @@ type FakeRESTClient struct { ...@@ -96,16 +96,16 @@ type FakeRESTClient struct {
} }
func (c *FakeRESTClient) Get() *Request { func (c *FakeRESTClient) Get() *Request {
return NewRequest(c, "GET", &url.URL{Host: "localhost"}, c.Codec) return NewRequest(c, "GET", &url.URL{Host: "localhost"}, c.Codec, true)
} }
func (c *FakeRESTClient) Put() *Request { func (c *FakeRESTClient) Put() *Request {
return NewRequest(c, "PUT", &url.URL{Host: "localhost"}, c.Codec) return NewRequest(c, "PUT", &url.URL{Host: "localhost"}, c.Codec, true)
} }
func (c *FakeRESTClient) Post() *Request { func (c *FakeRESTClient) Post() *Request {
return NewRequest(c, "POST", &url.URL{Host: "localhost"}, c.Codec) return NewRequest(c, "POST", &url.URL{Host: "localhost"}, c.Codec, true)
} }
func (c *FakeRESTClient) Delete() *Request { func (c *FakeRESTClient) Delete() *Request {
return NewRequest(c, "DELETE", &url.URL{Host: "localhost"}, c.Codec) return NewRequest(c, "DELETE", &url.URL{Host: "localhost"}, c.Codec, true)
} }
func (c *FakeRESTClient) Do(req *http.Request) (*http.Response, error) { func (c *FakeRESTClient) Do(req *http.Request) (*http.Response, error) {
c.Req = req c.Req = req
......
...@@ -117,7 +117,7 @@ func RESTClientFor(config *Config) (*RESTClient, error) { ...@@ -117,7 +117,7 @@ func RESTClientFor(config *Config) (*RESTClient, error) {
return nil, err return nil, err
} }
client := NewRESTClient(baseURL, versionInterfaces.Codec) client := NewRESTClient(baseURL, versionInterfaces.Codec, NamespaceInPathFor(version))
transport, err := TransportFor(config) transport, err := TransportFor(config)
if err != nil { if err != nil {
...@@ -252,3 +252,9 @@ func defaultVersionFor(config *Config) string { ...@@ -252,3 +252,9 @@ func defaultVersionFor(config *Config) string {
} }
return version 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")
}
...@@ -96,20 +96,23 @@ type Request struct { ...@@ -96,20 +96,23 @@ type Request struct {
sync bool sync bool
timeout time.Duration timeout time.Duration
// flag to control how to use namespace in urls
namespaceAsPath bool
// output // output
err error err error
body io.Reader body io.Reader
} }
// NewRequest creates a new request with the core attributes. // NewRequest creates a new request with the core attributes.
func NewRequest(client HTTPClient, verb string, baseURL *url.URL, codec runtime.Codec) *Request { func NewRequest(client HTTPClient, verb string, baseURL *url.URL, codec runtime.Codec, namespaceAsPath bool) *Request {
return &Request{ return &Request{
client: client, client: client,
verb: verb, verb: verb,
baseURL: baseURL, baseURL: baseURL,
codec: codec, codec: codec,
namespaceAsPath: namespaceAsPath,
path: baseURL.Path, path: baseURL.Path,
} }
} }
...@@ -136,8 +139,14 @@ func (r *Request) Namespace(namespace string) *Request { ...@@ -136,8 +139,14 @@ func (r *Request) Namespace(namespace string) *Request {
if r.err != nil { if r.err != nil {
return r return r
} }
if len(namespace) > 0 { if len(namespace) > 0 {
return r.Path("ns").Path(namespace) if r.namespaceAsPath {
return r.Path("ns").Path(namespace)
} else {
return r.setParam("namespace", namespace)
}
} }
return r return r
} }
......
...@@ -137,7 +137,7 @@ func TestTransformResponse(t *testing.T) { ...@@ -137,7 +137,7 @@ func TestTransformResponse(t *testing.T) {
{Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid}, {Response: &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(invalid))}, Data: invalid},
} }
for i, test := range testCases { for i, test := range testCases {
r := NewRequest(nil, "", uri, testapi.Codec()) r := NewRequest(nil, "", uri, testapi.Codec(), true)
if test.Response.Body == nil { if test.Response.Body == nil {
test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{})) test.Response.Body = ioutil.NopCloser(bytes.NewReader([]byte{}))
} }
......
...@@ -36,6 +36,10 @@ import ( ...@@ -36,6 +36,10 @@ import (
type RESTClient struct { type RESTClient struct {
baseURL *url.URL baseURL *url.URL
// namespaceInPath controls if URLs should encode the namespace as path param instead of query param
// needed for backward compatibility
namespaceInPath bool
// Codec is the encoding and decoding scheme that applies to a particular set of // Codec is the encoding and decoding scheme that applies to a particular set of
// REST resources. // REST resources.
Codec runtime.Codec Codec runtime.Codec
...@@ -56,7 +60,7 @@ type RESTClient struct { ...@@ -56,7 +60,7 @@ type RESTClient struct {
// NewRESTClient creates a new RESTClient. This client performs generic REST functions // 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 // such as Get, Put, Post, and Delete on specified paths. Codec controls encoding and
// decoding of responses from the server. // decoding of responses from the server.
func NewRESTClient(baseURL *url.URL, c runtime.Codec) *RESTClient { func NewRESTClient(baseURL *url.URL, c runtime.Codec, namespaceInPath bool) *RESTClient {
base := *baseURL base := *baseURL
if !strings.HasSuffix(base.Path, "/") { if !strings.HasSuffix(base.Path, "/") {
base.Path += "/" base.Path += "/"
...@@ -68,6 +72,8 @@ func NewRESTClient(baseURL *url.URL, c runtime.Codec) *RESTClient { ...@@ -68,6 +72,8 @@ func NewRESTClient(baseURL *url.URL, c runtime.Codec) *RESTClient {
baseURL: &base, baseURL: &base,
Codec: c, Codec: c,
namespaceInPath: namespaceInPath,
// Make asynchronous requests by default // Make asynchronous requests by default
Sync: false, Sync: false,
...@@ -98,7 +104,7 @@ func (c *RESTClient) Verb(verb string) *Request { ...@@ -98,7 +104,7 @@ func (c *RESTClient) Verb(verb string) *Request {
if poller == nil { if poller == nil {
poller = c.DefaultPoll poller = c.DefaultPoll
} }
return NewRequest(c.Client, verb, c.baseURL, c.Codec).Poller(poller).Sync(c.Sync).Timeout(c.Timeout) return NewRequest(c.Client, verb, c.baseURL, c.Codec, c.namespaceInPath).Poller(poller).Sync(c.Sync).Timeout(c.Timeout)
} }
// Post begins a POST request. Short for c.Verb("POST"). // Post begins a POST request. Short for c.Verb("POST").
......
...@@ -48,7 +48,7 @@ func getFakeClient(t *testing.T, validURLs []string) (ClientPosterFunc, *httptes ...@@ -48,7 +48,7 @@ func getFakeClient(t *testing.T, validURLs []string) (ClientPosterFunc, *httptes
return func(mapping *meta.RESTMapping) (RESTClientPoster, error) { return func(mapping *meta.RESTMapping) (RESTClientPoster, error) {
fakeCodec := runtime.CodecFor(api.Scheme, "v1beta1") fakeCodec := runtime.CodecFor(api.Scheme, "v1beta1")
fakeUri, _ := url.Parse(server.URL + "/api/v1beta1") fakeUri, _ := url.Parse(server.URL + "/api/v1beta1")
return client.NewRESTClient(fakeUri, fakeCodec), nil return client.NewRESTClient(fakeUri, fakeCodec, false), nil
}, server }, server
} }
......
...@@ -37,6 +37,13 @@ import ( ...@@ -37,6 +37,13 @@ import (
"github.com/coreos/go-etcd/etcd" "github.com/coreos/go-etcd/etcd"
) )
func makeNamespaceURL(namespace, suffix string) string {
if client.NamespaceInPathFor(testapi.Version()) {
return makeURL("/ns/" + namespace + suffix)
}
return makeURL(suffix + "?namespace=" + namespace)
}
func makeURL(suffix string) string { func makeURL(suffix string) string {
return path.Join("/api", testapi.Version(), suffix) return path.Join("/api", testapi.Version(), suffix)
} }
...@@ -221,7 +228,7 @@ func TestCreateReplica(t *testing.T) { ...@@ -221,7 +228,7 @@ func TestCreateReplica(t *testing.T) {
}, },
Spec: controllerSpec.Spec.Template.Spec, Spec: controllerSpec.Spec.Template.Spec,
} }
fakeHandler.ValidateRequest(t, makeURL("/ns/default/pods"), "POST", nil) fakeHandler.ValidateRequest(t, makeNamespaceURL("default", "/pods"), "POST", nil)
actualPod, err := client.Codec.Decode([]byte(fakeHandler.RequestBody)) actualPod, err := client.Codec.Decode([]byte(fakeHandler.RequestBody))
if err != nil { if err != nil {
t.Errorf("Unexpected error: %#v", err) t.Errorf("Unexpected error: %#v", err)
......
...@@ -204,7 +204,7 @@ func (factory *ConfigFactory) pollMinions() (cache.Enumerator, error) { ...@@ -204,7 +204,7 @@ func (factory *ConfigFactory) pollMinions() (cache.Enumerator, error) {
func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue *cache.FIFO) func(pod *api.Pod, err error) { func (factory *ConfigFactory) makeDefaultErrorFunc(backoff *podBackoff, podQueue *cache.FIFO) func(pod *api.Pod, err error) {
return func(pod *api.Pod, err error) { return func(pod *api.Pod, err error) {
glog.Errorf("Error scheduling %v: %v; retrying", pod.Name, err) glog.Errorf("Error scheduling %v %v: %v; retrying", pod.Namespace, pod.Name, err)
backoff.gc() backoff.gc()
// Retry asynchronously. // Retry asynchronously.
// Note that this is extremely rudimentary and we need a more real error handling path. // Note that this is extremely rudimentary and we need a more real error handling path.
......
...@@ -19,6 +19,7 @@ package factory ...@@ -19,6 +19,7 @@ package factory
import ( import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"path"
"reflect" "reflect"
"testing" "testing"
"time" "time"
...@@ -183,6 +184,22 @@ func TestPollMinions(t *testing.T) { ...@@ -183,6 +184,22 @@ func TestPollMinions(t *testing.T) {
} }
} }
func makeNamespaceURL(namespace, suffix string, isClient bool) string {
if client.NamespaceInPathFor(testapi.Version()) {
return makeURL("/ns/" + namespace + suffix)
}
// if this is a url the client should call, encode the url
if isClient {
return makeURL(suffix + "?namespace=" + namespace)
}
// its not a client url, so its what the server needs to listen on
return makeURL(suffix)
}
func makeURL(suffix string) string {
return path.Join("/api", testapi.Version(), suffix)
}
func TestDefaultErrorFunc(t *testing.T) { func TestDefaultErrorFunc(t *testing.T) {
testPod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"}} testPod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", Namespace: "bar"}}
handler := util.FakeHandler{ handler := util.FakeHandler{
...@@ -191,8 +208,9 @@ func TestDefaultErrorFunc(t *testing.T) { ...@@ -191,8 +208,9 @@ func TestDefaultErrorFunc(t *testing.T) {
T: t, T: t,
} }
mux := http.NewServeMux() mux := http.NewServeMux()
// FakeHandler musn't be sent requests other than the one you want to test. // FakeHandler musn't be sent requests other than the one you want to test.
mux.Handle("/api/"+testapi.Version()+"/ns/bar/pods/foo", &handler) mux.Handle(makeNamespaceURL("bar", "/pods/foo", false), &handler)
server := httptest.NewServer(mux) server := httptest.NewServer(mux)
defer server.Close() defer server.Close()
factory := NewConfigFactory(client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()})) factory := NewConfigFactory(client.NewOrDie(&client.Config{Host: server.URL, Version: testapi.Version()}))
...@@ -213,7 +231,7 @@ func TestDefaultErrorFunc(t *testing.T) { ...@@ -213,7 +231,7 @@ func TestDefaultErrorFunc(t *testing.T) {
if !exists { if !exists {
continue continue
} }
handler.ValidateRequest(t, "/api/"+testapi.Version()+"/ns/bar/pods/foo", "GET", nil) handler.ValidateRequest(t, makeNamespaceURL("bar", "/pods/foo", true), "GET", nil)
if e, a := testPod, got; !reflect.DeepEqual(e, a) { if e, a := testPod, got; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %v, got %v", e, a) t.Errorf("Expected %v, got %v", e, a)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment