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
7cf66443
Commit
7cf66443
authored
Dec 09, 2014
by
derekwaynecarr
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move namespace from query param to path part
parent
58ba3c7f
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
388 additions
and
156 deletions
+388
-156
apiserver.go
pkg/apiserver/apiserver.go
+1
-0
apiserver_test.go
pkg/apiserver/apiserver_test.go
+2
-2
handlers.go
pkg/apiserver/handlers.go
+81
-20
handlers_test.go
pkg/apiserver/handlers_test.go
+75
-0
proxy.go
pkg/apiserver/proxy.go
+10
-14
proxy_test.go
pkg/apiserver/proxy_test.go
+28
-21
redirect.go
pkg/apiserver/redirect.go
+10
-9
redirect_test.go
pkg/apiserver/redirect_test.go
+53
-0
resthandler.go
pkg/apiserver/resthandler.go
+27
-27
watch.go
pkg/apiserver/watch.go
+9
-7
client_test.go
pkg/client/client_test.go
+57
-34
request.go
pkg/client/request.go
+1
-1
replication_controller_test.go
pkg/controller/replication_controller_test.go
+1
-1
resthelper.go
pkg/kubectl/resthelper.go
+5
-5
resthelper_test.go
pkg/kubectl/resthelper_test.go
+26
-13
factory_test.go
plugin/pkg/scheduler/factory/factory_test.go
+2
-2
No files found.
pkg/apiserver/apiserver.go
View file @
7cf66443
...
@@ -222,6 +222,7 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container, root string,
...
@@ -222,6 +222,7 @@ func (g *APIGroupVersion) InstallREST(container *restful.Container, root string,
for
path
,
storage
:=
range
g
.
handler
.
storage
{
for
path
,
storage
:=
range
g
.
handler
.
storage
{
registerResourceHandlers
(
ws
,
version
,
path
,
storage
,
kinds
,
h
)
registerResourceHandlers
(
ws
,
version
,
path
,
storage
,
kinds
,
h
)
registerResourceHandlers
(
ws
,
version
,
"ns/{namespace}/"
+
path
,
storage
,
kinds
,
h
)
}
}
// TODO: port the rest of these. Sadly, if we don't, we'll have inconsistent
// TODO: port the rest of these. Sadly, if we don't, we'll have inconsistent
...
...
pkg/apiserver/apiserver_test.go
View file @
7cf66443
...
@@ -683,7 +683,7 @@ func TestSyncCreate(t *testing.T) {
...
@@ -683,7 +683,7 @@ func TestSyncCreate(t *testing.T) {
t
:
t
,
t
:
t
,
name
:
"bar"
,
name
:
"bar"
,
namespace
:
"other"
,
namespace
:
"other"
,
expectedSet
:
"/prefix/version/
foo/bar?namespace=othe
r"
,
expectedSet
:
"/prefix/version/
ns/other/foo/ba
r"
,
}
}
handler
:=
Handle
(
map
[
string
]
RESTStorage
{
handler
:=
Handle
(
map
[
string
]
RESTStorage
{
"foo"
:
&
storage
,
"foo"
:
&
storage
,
...
@@ -696,7 +696,7 @@ func TestSyncCreate(t *testing.T) {
...
@@ -696,7 +696,7 @@ func TestSyncCreate(t *testing.T) {
Other
:
"bar"
,
Other
:
"bar"
,
}
}
data
,
_
:=
codec
.
Encode
(
simple
)
data
,
_
:=
codec
.
Encode
(
simple
)
request
,
err
:=
http
.
NewRequest
(
"POST"
,
server
.
URL
+
"/prefix/version/foo?sync=true"
,
bytes
.
NewBuffer
(
data
))
request
,
err
:=
http
.
NewRequest
(
"POST"
,
server
.
URL
+
"/prefix/version/
ns/other/
foo?sync=true"
,
bytes
.
NewBuffer
(
data
))
if
err
!=
nil
{
if
err
!=
nil
{
t
.
Errorf
(
"unexpected error: %v"
,
err
)
t
.
Errorf
(
"unexpected error: %v"
,
err
)
}
}
...
...
pkg/apiserver/handlers.go
View file @
7cf66443
...
@@ -23,6 +23,7 @@ import (
...
@@ -23,6 +23,7 @@ import (
"runtime/debug"
"runtime/debug"
"strings"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer"
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/authorizer"
authhandlers
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/handlers"
authhandlers
"github.com/GoogleCloudPlatform/kubernetes/pkg/auth/handlers"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
"github.com/GoogleCloudPlatform/kubernetes/pkg/httplog"
...
@@ -40,24 +41,6 @@ var specialVerbs = map[string]bool{
...
@@ -40,24 +41,6 @@ var specialVerbs = map[string]bool{
"watch"
:
true
,
"watch"
:
true
,
}
}
// KindFromRequest returns Kind if Kind can be extracted from the request. Otherwise, the empty string.
func
KindFromRequest
(
req
http
.
Request
)
string
{
// TODO: find a way to keep this code's assumptions about paths up to date with changes in the code. Maybe instead
// of directly adding handler's code to the master's Mux, have a function which forces the structure when adding
// them.
parts
:=
splitPath
(
req
.
URL
.
Path
)
if
len
(
parts
)
>
2
&&
parts
[
0
]
==
"api"
{
if
_
,
ok
:=
specialVerbs
[
parts
[
2
]];
ok
{
if
len
(
parts
)
>
3
{
return
parts
[
3
]
}
}
else
{
return
parts
[
2
]
}
}
return
""
}
// IsReadOnlyReq() is true for any (or at least many) request which has no observable
// IsReadOnlyReq() is true for any (or at least many) request which has no observable
// side effects on state of apiserver (though there may be internal side effects like
// side effects on state of apiserver (though there may be internal side effects like
// caching and logging).
// caching and logging).
...
@@ -185,14 +168,16 @@ func (r *requestAttributeGetter) GetAttribs(req *http.Request) authorizer.Attrib
...
@@ -185,14 +168,16 @@ func (r *requestAttributeGetter) GetAttribs(req *http.Request) authorizer.Attrib
attribs
.
ReadOnly
=
IsReadOnlyReq
(
*
req
)
attribs
.
ReadOnly
=
IsReadOnlyReq
(
*
req
)
namespace
,
kind
,
_
,
_
:=
KindAndNamespace
(
req
)
// If a path follows the conventions of the REST object store, then
// If a path follows the conventions of the REST object store, then
// we can extract the object Kind. Otherwise, not.
// we can extract the object Kind. Otherwise, not.
attribs
.
Kind
=
KindFromRequest
(
*
req
)
attribs
.
Kind
=
kind
// If the request specifies a namespace, then the namespace is filled in.
// If the request specifies a namespace, then the namespace is filled in.
// Assumes there is no empty string namespace. Unspecified results
// Assumes there is no empty string namespace. Unspecified results
// in empty (does not understand defaulting rules.)
// in empty (does not understand defaulting rules.)
attribs
.
Namespace
=
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
attribs
.
Namespace
=
namespace
return
&
attribs
return
&
attribs
}
}
...
@@ -208,3 +193,79 @@ func WithAuthorizationCheck(handler http.Handler, getAttribs RequestAttributeGet
...
@@ -208,3 +193,79 @@ func WithAuthorizationCheck(handler http.Handler, getAttribs RequestAttributeGet
forbidden
(
w
,
req
)
forbidden
(
w
,
req
)
})
})
}
}
// KindAndNamespace returns the kind, namespace, and path parts for the request relative to /{kind}/{name}
// Valid Inputs:
// Storage paths
// /ns/{namespace}/{kind}
// /ns/{namespace}/{kind}/{resourceName}
// /{kind}
// /{kind}/{resourceName}
// /{kind}/{resourceName}?namespace={namespace}
// /{kind}?namespace={namespace}
//
// Special verbs:
// /proxy/{kind}/{resourceName}
// /proxy/ns/{namespace}/{kind}/{resourceName}
// /redirect/ns/{namespace}/{kind}/{resourceName}
// /redirect/{kind}/{resourceName}
// /watch/{kind}
// /watch/ns/{namespace}/{kind}
//
// Fully qualified paths for above:
// /api/{version}/*
// /api/{version}/*
func
KindAndNamespace
(
req
*
http
.
Request
)
(
namespace
,
kind
string
,
parts
[]
string
,
err
error
)
{
parts
=
splitPath
(
req
.
URL
.
Path
)
if
len
(
parts
)
<
1
{
err
=
fmt
.
Errorf
(
"Unable to determine kind and namespace from an empty URL path"
)
return
}
// handle input of form /api/{version}/* by adjusting special paths
if
parts
[
0
]
==
"api"
{
if
len
(
parts
)
>
2
{
parts
=
parts
[
2
:
]
}
else
{
err
=
fmt
.
Errorf
(
"Unable to determine kind and namespace from url, %v"
,
req
.
URL
)
return
}
}
// handle input of form /{specialVerb}/*
if
_
,
ok
:=
specialVerbs
[
parts
[
0
]];
ok
{
if
len
(
parts
)
>
1
{
parts
=
parts
[
1
:
]
}
else
{
err
=
fmt
.
Errorf
(
"Unable to determine kind and namespace from url, %v"
,
req
.
URL
)
return
}
}
// URL forms: /ns/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
if
parts
[
0
]
==
"ns"
{
if
len
(
parts
)
<
3
{
err
=
fmt
.
Errorf
(
"ResourceTypeAndNamespace expects a path of form /ns/{namespace}/*"
)
return
}
namespace
=
parts
[
1
]
kind
=
parts
[
2
]
parts
=
parts
[
2
:
]
return
}
// URL forms: /{kind}/*
// URL forms: POST /{kind} is a legacy API convention to create in "default" namespace
// URL forms: /{kind}/{resourceName} use the "default" namespace if omitted from query param
// URL forms: /{kind} assume cross-namespace operation if omitted from query param
kind
=
parts
[
0
]
namespace
=
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
if
len
(
namespace
)
==
0
{
if
len
(
parts
)
>
1
||
req
.
Method
==
"POST"
{
namespace
=
api
.
NamespaceDefault
}
else
{
namespace
=
api
.
NamespaceAll
}
}
return
}
pkg/apiserver/handlers_test.go
View file @
7cf66443
...
@@ -19,7 +19,10 @@ package apiserver
...
@@ -19,7 +19,10 @@ package apiserver
import
(
import
(
"net/http"
"net/http"
"net/http/httptest"
"net/http/httptest"
"reflect"
"testing"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)
)
type
fakeRL
bool
type
fakeRL
bool
...
@@ -59,3 +62,75 @@ func TestReadOnly(t *testing.T) {
...
@@ -59,3 +62,75 @@ func TestReadOnly(t *testing.T) {
http
.
DefaultClient
.
Do
(
req
)
http
.
DefaultClient
.
Do
(
req
)
}
}
}
}
func
TestKindAndNamespace
(
t
*
testing
.
T
)
{
successCases
:=
[]
struct
{
url
string
expectedNamespace
string
expectedKind
string
expectedParts
[]
string
}{
// resource paths
{
"/ns/other/pods"
,
"other"
,
"pods"
,
[]
string
{
"pods"
}},
{
"/ns/other/pods/foo"
,
"other"
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/pods"
,
api
.
NamespaceAll
,
"pods"
,
[]
string
{
"pods"
}},
{
"/pods/foo"
,
api
.
NamespaceDefault
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/pods/foo?namespace=other"
,
"other"
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/pods?namespace=other"
,
"other"
,
"pods"
,
[]
string
{
"pods"
}},
// special verbs
{
"/proxy/ns/other/pods/foo"
,
"other"
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/proxy/pods/foo"
,
api
.
NamespaceDefault
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/redirect/ns/other/pods/foo"
,
"other"
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/redirect/pods/foo"
,
api
.
NamespaceDefault
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/watch/pods"
,
api
.
NamespaceAll
,
"pods"
,
[]
string
{
"pods"
}},
{
"/watch/ns/other/pods"
,
"other"
,
"pods"
,
[]
string
{
"pods"
}},
// full-qualified paths
{
"/api/v1beta1/ns/other/pods"
,
"other"
,
"pods"
,
[]
string
{
"pods"
}},
{
"/api/v1beta1/ns/other/pods/foo"
,
"other"
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/api/v1beta1/pods"
,
api
.
NamespaceAll
,
"pods"
,
[]
string
{
"pods"
}},
{
"/api/v1beta1/pods/foo"
,
api
.
NamespaceDefault
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/api/v1beta1/pods/foo?namespace=other"
,
"other"
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/api/v1beta1/pods?namespace=other"
,
"other"
,
"pods"
,
[]
string
{
"pods"
}},
{
"/api/v1beta1/proxy/pods/foo"
,
api
.
NamespaceDefault
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/api/v1beta1/redirect/pods/foo"
,
api
.
NamespaceDefault
,
"pods"
,
[]
string
{
"pods"
,
"foo"
}},
{
"/api/v1beta1/watch/pods"
,
api
.
NamespaceAll
,
"pods"
,
[]
string
{
"pods"
}},
{
"/api/v1beta1/watch/ns/other/pods"
,
"other"
,
"pods"
,
[]
string
{
"pods"
}},
}
for
_
,
successCase
:=
range
successCases
{
req
,
_
:=
http
.
NewRequest
(
"GET"
,
successCase
.
url
,
nil
)
namespace
,
kind
,
parts
,
err
:=
KindAndNamespace
(
req
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error for url: %s"
,
successCase
.
url
)
}
if
successCase
.
expectedNamespace
!=
namespace
{
t
.
Errorf
(
"Unexpected namespace for url: %s, expected: %s, actual: %s"
,
successCase
.
url
,
successCase
.
expectedNamespace
,
namespace
)
}
if
successCase
.
expectedKind
!=
kind
{
t
.
Errorf
(
"Unexpected resourceType for url: %s, expected: %s, actual: %s"
,
successCase
.
url
,
successCase
.
expectedKind
,
kind
)
}
if
!
reflect
.
DeepEqual
(
successCase
.
expectedParts
,
parts
)
{
t
.
Errorf
(
"Unexpected parts for url: %s, expected: %v, actual: %v"
,
successCase
.
url
,
successCase
.
expectedParts
,
parts
)
}
}
errorCases
:=
map
[
string
]
string
{
"no resource path"
:
"/"
,
"missing resource type"
:
"/ns/other"
,
"just apiversion"
:
"/api/v1beta1/"
,
"apiversion with no resource"
:
"/api/v1beta1/"
,
"apiversion with just namespace"
:
"/api/v1beta1/ns/other"
,
}
for
k
,
v
:=
range
errorCases
{
req
,
err
:=
http
.
NewRequest
(
"GET"
,
v
,
nil
)
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error %v"
,
err
)
}
_
,
_
,
_
,
err
=
KindAndNamespace
(
req
)
if
err
==
nil
{
t
.
Errorf
(
"Expected error for key: %s"
,
k
)
}
}
}
pkg/apiserver/proxy.go
View file @
7cf66443
...
@@ -78,35 +78,31 @@ type ProxyHandler struct {
...
@@ -78,35 +78,31 @@ type ProxyHandler struct {
}
}
func
(
r
*
ProxyHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
r
*
ProxyHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
// use the default namespace to address the service
namespace
,
kind
,
parts
,
err
:=
KindAndNamespace
(
req
)
ctx
:=
api
.
NewDefaultContext
()
if
err
!=
nil
{
// if not in default namespace, provide the query parameter
notFound
(
w
,
req
)
// TODO this will need to go in the path in the future and not as a query parameter
return
namespace
:=
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
}
if
len
(
namespace
)
>
0
{
ctx
:=
api
.
WithNamespace
(
api
.
NewContext
(),
namespace
)
ctx
=
api
.
WithNamespace
(
ctx
,
namespace
)
}
parts
:=
strings
.
SplitN
(
req
.
URL
.
Path
,
"/"
,
3
)
if
len
(
parts
)
<
2
{
if
len
(
parts
)
<
2
{
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
resourceName
:=
parts
[
0
]
id
:=
parts
[
1
]
id
:=
parts
[
1
]
rest
:=
""
rest
:=
""
if
len
(
parts
)
==
3
{
if
len
(
parts
)
==
3
{
rest
=
parts
[
2
]
rest
=
parts
[
2
]
}
}
storage
,
ok
:=
r
.
storage
[
resourceName
]
storage
,
ok
:=
r
.
storage
[
kind
]
if
!
ok
{
if
!
ok
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' has no storage object"
,
resourceName
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' has no storage object"
,
kind
)
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
redirector
,
ok
:=
storage
.
(
Redirector
)
redirector
,
ok
:=
storage
.
(
Redirector
)
if
!
ok
{
if
!
ok
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' is not a redirector"
,
resourceName
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' is not a redirector"
,
kind
)
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
...
@@ -150,7 +146,7 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
...
@@ -150,7 +146,7 @@ func (r *ProxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
proxy
.
Transport
=
&
proxyTransport
{
proxy
.
Transport
=
&
proxyTransport
{
proxyScheme
:
req
.
URL
.
Scheme
,
proxyScheme
:
req
.
URL
.
Scheme
,
proxyHost
:
req
.
URL
.
Host
,
proxyHost
:
req
.
URL
.
Host
,
proxyPathPrepend
:
path
.
Join
(
r
.
prefix
,
resourceName
,
id
),
proxyPathPrepend
:
path
.
Join
(
r
.
prefix
,
"ns"
,
namespace
,
kind
,
id
),
}
}
proxy
.
FlushInterval
=
200
*
time
.
Millisecond
proxy
.
FlushInterval
=
200
*
time
.
Millisecond
proxy
.
ServeHTTP
(
w
,
newReq
)
proxy
.
ServeHTTP
(
w
,
newReq
)
...
...
pkg/apiserver/proxy_test.go
View file @
7cf66443
...
@@ -142,7 +142,7 @@ func TestProxy(t *testing.T) {
...
@@ -142,7 +142,7 @@ func TestProxy(t *testing.T) {
{
"POST"
,
"/some/other/dir"
,
"question"
,
"answer"
,
"default"
},
{
"POST"
,
"/some/other/dir"
,
"question"
,
"answer"
,
"default"
},
{
"PUT"
,
"/some/dir/id"
,
"different question"
,
"answer"
,
"default"
},
{
"PUT"
,
"/some/dir/id"
,
"different question"
,
"answer"
,
"default"
},
{
"DELETE"
,
"/some/dir/id"
,
""
,
"ok"
,
"default"
},
{
"DELETE"
,
"/some/dir/id"
,
""
,
"ok"
,
"default"
},
{
"GET"
,
"/some/dir/id
?namespace=other
"
,
""
,
"answer"
,
"other"
},
{
"GET"
,
"/some/dir/id"
,
""
,
"answer"
,
"other"
},
}
}
for
_
,
item
:=
range
table
{
for
_
,
item
:=
range
table
{
...
@@ -169,27 +169,34 @@ func TestProxy(t *testing.T) {
...
@@ -169,27 +169,34 @@ func TestProxy(t *testing.T) {
server
:=
httptest
.
NewServer
(
handler
)
server
:=
httptest
.
NewServer
(
handler
)
defer
server
.
Close
()
defer
server
.
Close
()
req
,
err
:=
http
.
NewRequest
(
// test each supported URL pattern for finding the redirection resource in the proxy in a particular namespace
item
.
method
,
proxyTestPatterns
:=
[]
string
{
server
.
URL
+
"/prefix/version/proxy/foo/id"
+
item
.
path
,
"/prefix/version/proxy/foo/id"
+
item
.
path
+
"?namespace="
+
item
.
reqNamespace
,
strings
.
NewReader
(
item
.
reqBody
),
"/prefix/version/proxy/ns/"
+
item
.
reqNamespace
+
"/foo/id"
+
item
.
path
,
)
if
err
!=
nil
{
t
.
Errorf
(
"%v - unexpected error %v"
,
item
.
method
,
err
)
continue
}
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
if
err
!=
nil
{
t
.
Errorf
(
"%v - unexpected error %v"
,
item
.
method
,
err
)
continue
}
}
gotResp
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
for
_
,
proxyTestPattern
:=
range
proxyTestPatterns
{
if
err
!=
nil
{
req
,
err
:=
http
.
NewRequest
(
t
.
Errorf
(
"%v - unexpected error %v"
,
item
.
method
,
err
)
item
.
method
,
}
server
.
URL
+
proxyTestPattern
,
resp
.
Body
.
Close
()
strings
.
NewReader
(
item
.
reqBody
),
if
e
,
a
:=
item
.
respBody
,
string
(
gotResp
);
e
!=
a
{
)
t
.
Errorf
(
"%v - expected %v, got %v"
,
item
.
method
,
e
,
a
)
if
err
!=
nil
{
t
.
Errorf
(
"%v - unexpected error %v"
,
item
.
method
,
err
)
continue
}
resp
,
err
:=
http
.
DefaultClient
.
Do
(
req
)
if
err
!=
nil
{
t
.
Errorf
(
"%v - unexpected error %v"
,
item
.
method
,
err
)
continue
}
gotResp
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
t
.
Errorf
(
"%v - unexpected error %v"
,
item
.
method
,
err
)
}
resp
.
Body
.
Close
()
if
e
,
a
:=
item
.
respBody
,
string
(
gotResp
);
e
!=
a
{
t
.
Errorf
(
"%v - expected %v, got %v"
,
item
.
method
,
e
,
a
)
}
}
}
}
}
}
}
pkg/apiserver/redirect.go
View file @
7cf66443
...
@@ -30,28 +30,29 @@ type RedirectHandler struct {
...
@@ -30,28 +30,29 @@ type RedirectHandler struct {
}
}
func
(
r
*
RedirectHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
r
*
RedirectHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
ctx
:=
api
.
NewDefaultContext
(
)
namespace
,
kind
,
parts
,
err
:=
KindAndNamespace
(
req
)
namespace
:=
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
if
err
!=
nil
{
if
len
(
namespace
)
>
0
{
notFound
(
w
,
req
)
ctx
=
api
.
WithNamespace
(
ctx
,
namespace
)
return
}
}
parts
:=
splitPath
(
req
.
URL
.
Path
)
ctx
:=
api
.
WithNamespace
(
api
.
NewContext
(),
namespace
)
// redirection requires /kind/resourceName path parts
if
len
(
parts
)
!=
2
||
req
.
Method
!=
"GET"
{
if
len
(
parts
)
!=
2
||
req
.
Method
!=
"GET"
{
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
resourceName
:=
parts
[
0
]
id
:=
parts
[
1
]
id
:=
parts
[
1
]
storage
,
ok
:=
r
.
storage
[
resourceName
]
storage
,
ok
:=
r
.
storage
[
kind
]
if
!
ok
{
if
!
ok
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' has no storage object"
,
resourceName
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' has no storage object"
,
kind
)
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
redirector
,
ok
:=
storage
.
(
Redirector
)
redirector
,
ok
:=
storage
.
(
Redirector
)
if
!
ok
{
if
!
ok
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' is not a redirector"
,
resourceName
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' is not a redirector"
,
kind
)
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
...
...
pkg/apiserver/redirect_test.go
View file @
7cf66443
...
@@ -76,3 +76,56 @@ func TestRedirect(t *testing.T) {
...
@@ -76,3 +76,56 @@ func TestRedirect(t *testing.T) {
}
}
}
}
}
}
func
TestRedirectWithNamespaces
(
t
*
testing
.
T
)
{
simpleStorage
:=
&
SimpleRESTStorage
{
errors
:
map
[
string
]
error
{},
expectedResourceNamespace
:
"other"
,
}
handler
:=
Handle
(
map
[
string
]
RESTStorage
{
"foo"
:
simpleStorage
,
},
codec
,
"/prefix"
,
"version"
,
selfLinker
)
server
:=
httptest
.
NewServer
(
handler
)
defer
server
.
Close
()
dontFollow
:=
errors
.
New
(
"don't follow"
)
client
:=
http
.
Client
{
CheckRedirect
:
func
(
req
*
http
.
Request
,
via
[]
*
http
.
Request
)
error
{
return
dontFollow
},
}
table
:=
[]
struct
{
id
string
err
error
code
int
}{
{
"cozy"
,
nil
,
http
.
StatusTemporaryRedirect
},
{
"horse"
,
errors
.
New
(
"no such id"
),
http
.
StatusInternalServerError
},
}
for
_
,
item
:=
range
table
{
simpleStorage
.
errors
[
"resourceLocation"
]
=
item
.
err
simpleStorage
.
resourceLocation
=
item
.
id
resp
,
err
:=
client
.
Get
(
server
.
URL
+
"/prefix/version/redirect/ns/other/foo/"
+
item
.
id
)
if
resp
==
nil
{
t
.
Fatalf
(
"Unexpected nil resp"
)
}
resp
.
Body
.
Close
()
if
e
,
a
:=
item
.
code
,
resp
.
StatusCode
;
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
if
e
,
a
:=
item
.
id
,
simpleStorage
.
requestedResourceLocationID
;
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
if
item
.
err
!=
nil
{
continue
}
if
err
==
nil
||
err
.
(
*
url
.
Error
)
.
Err
!=
dontFollow
{
t
.
Errorf
(
"Unexpected err %#v"
,
err
)
}
if
e
,
a
:=
item
.
id
,
resp
.
Header
.
Get
(
"Location"
);
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
}
}
pkg/apiserver/resthandler.go
View file @
7cf66443
...
@@ -41,19 +41,19 @@ type RESTHandler struct {
...
@@ -41,19 +41,19 @@ type RESTHandler struct {
// ServeHTTP handles requests to all RESTStorage objects.
// ServeHTTP handles requests to all RESTStorage objects.
func
(
h
*
RESTHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
h
*
RESTHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
parts
:=
splitPath
(
req
.
URL
.
Path
)
namespace
,
kind
,
parts
,
err
:=
KindAndNamespace
(
req
)
if
len
(
parts
)
<
1
{
if
err
!=
nil
{
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
storage
:=
h
.
storage
[
parts
[
0
]
]
storage
:=
h
.
storage
[
kind
]
if
storage
==
nil
{
if
storage
==
nil
{
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' has no storage object"
,
parts
[
0
]
)
httplog
.
LogOf
(
req
,
w
)
.
Addf
(
"'%v' has no storage object"
,
kind
)
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
h
.
handleRESTStorage
(
parts
,
req
,
w
,
storage
)
h
.
handleRESTStorage
(
parts
,
req
,
w
,
storage
,
namespace
)
}
}
// Sets the SelfLink field of the object.
// Sets the SelfLink field of the object.
...
@@ -66,12 +66,17 @@ func (h *RESTHandler) setSelfLink(obj runtime.Object, req *http.Request) error {
...
@@ -66,12 +66,17 @@ func (h *RESTHandler) setSelfLink(obj runtime.Object, req *http.Request) error {
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
// TODO Remove this when namespace is in path
// we need to add namespace as a query param, if its not in the resource path
if
len
(
namespace
)
>
0
{
if
len
(
namespace
)
>
0
{
query
:=
newURL
.
Query
()
parts
:=
splitPath
(
req
.
URL
.
Path
)
query
.
Set
(
"namespace"
,
namespace
)
if
parts
[
0
]
!=
"ns"
{
newURL
.
RawQuery
=
query
.
Encode
()
query
:=
newURL
.
Query
()
query
.
Set
(
"namespace"
,
namespace
)
newURL
.
RawQuery
=
query
.
Encode
()
}
}
}
err
=
h
.
selfLinker
.
SetSelfLink
(
obj
,
newURL
.
String
())
err
=
h
.
selfLinker
.
SetSelfLink
(
obj
,
newURL
.
String
())
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -107,11 +112,14 @@ func (h *RESTHandler) setSelfLinkAddName(obj runtime.Object, req *http.Request)
...
@@ -107,11 +112,14 @@ func (h *RESTHandler) setSelfLinkAddName(obj runtime.Object, req *http.Request)
newURL
.
Path
=
path
.
Join
(
h
.
canonicalPrefix
,
req
.
URL
.
Path
,
name
)
newURL
.
Path
=
path
.
Join
(
h
.
canonicalPrefix
,
req
.
URL
.
Path
,
name
)
newURL
.
RawQuery
=
""
newURL
.
RawQuery
=
""
newURL
.
Fragment
=
""
newURL
.
Fragment
=
""
//
TODO Remove this when namespace is in
path
//
we need to add namespace as a query param, if its not in the resource
path
if
len
(
namespace
)
>
0
{
if
len
(
namespace
)
>
0
{
query
:=
newURL
.
Query
()
parts
:=
splitPath
(
req
.
URL
.
Path
)
query
.
Set
(
"namespace"
,
namespace
)
if
parts
[
0
]
!=
"ns"
{
newURL
.
RawQuery
=
query
.
Encode
()
query
:=
newURL
.
Query
()
query
.
Set
(
"namespace"
,
namespace
)
newURL
.
RawQuery
=
query
.
Encode
()
}
}
}
return
h
.
selfLinker
.
SetSelfLink
(
obj
,
newURL
.
String
())
return
h
.
selfLinker
.
SetSelfLink
(
obj
,
newURL
.
String
())
}
}
...
@@ -138,18 +146,10 @@ func curry(f func(runtime.Object, *http.Request) error, req *http.Request) func(
...
@@ -138,18 +146,10 @@ func curry(f func(runtime.Object, *http.Request) error, req *http.Request) func(
// sync=[false|true] Synchronous request (only applies to create, update, delete operations)
// sync=[false|true] Synchronous request (only applies to create, update, delete operations)
// timeout=<duration> Timeout for synchronous requests, only applies if sync=true
// timeout=<duration> Timeout for synchronous requests, only applies if sync=true
// labels=<label-selector> Used for filtering list operations
// labels=<label-selector> Used for filtering list operations
func
(
h
*
RESTHandler
)
handleRESTStorage
(
parts
[]
string
,
req
*
http
.
Request
,
w
http
.
ResponseWriter
,
storage
RESTStorage
)
{
func
(
h
*
RESTHandler
)
handleRESTStorage
(
parts
[]
string
,
req
*
http
.
Request
,
w
http
.
ResponseWriter
,
storage
RESTStorage
,
namespace
string
)
{
ctx
:=
api
.
NewContext
(
)
ctx
:=
api
.
WithNamespace
(
api
.
NewContext
(),
namespace
)
sync
:=
req
.
URL
.
Query
()
.
Get
(
"sync"
)
==
"true"
sync
:=
req
.
URL
.
Query
()
.
Get
(
"sync"
)
==
"true"
timeout
:=
parseTimeout
(
req
.
URL
.
Query
()
.
Get
(
"timeout"
))
timeout
:=
parseTimeout
(
req
.
URL
.
Query
()
.
Get
(
"timeout"
))
// TODO for now, we pull namespace from query parameter, but according to spec, it must go in resource path in future PR
// if a namespace if specified, it's always used.
// for list/watch operations, a namespace is not required if omitted.
// for all other operations, if namespace is omitted, we will default to default namespace.
namespace
:=
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
if
len
(
namespace
)
>
0
{
ctx
=
api
.
WithNamespace
(
ctx
,
namespace
)
}
switch
req
.
Method
{
switch
req
.
Method
{
case
"GET"
:
case
"GET"
:
switch
len
(
parts
)
{
switch
len
(
parts
)
{
...
@@ -175,7 +175,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
...
@@ -175,7 +175,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
}
}
writeJSON
(
http
.
StatusOK
,
h
.
codec
,
list
,
w
)
writeJSON
(
http
.
StatusOK
,
h
.
codec
,
list
,
w
)
case
2
:
case
2
:
item
,
err
:=
storage
.
Get
(
api
.
WithNamespaceDefaultIfNone
(
ctx
)
,
parts
[
1
])
item
,
err
:=
storage
.
Get
(
ctx
,
parts
[
1
])
if
err
!=
nil
{
if
err
!=
nil
{
errorJSON
(
err
,
h
.
codec
,
w
)
errorJSON
(
err
,
h
.
codec
,
w
)
return
return
...
@@ -205,7 +205,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
...
@@ -205,7 +205,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
errorJSON
(
err
,
h
.
codec
,
w
)
errorJSON
(
err
,
h
.
codec
,
w
)
return
return
}
}
out
,
err
:=
storage
.
Create
(
api
.
WithNamespaceDefaultIfNone
(
ctx
)
,
obj
)
out
,
err
:=
storage
.
Create
(
ctx
,
obj
)
if
err
!=
nil
{
if
err
!=
nil
{
errorJSON
(
err
,
h
.
codec
,
w
)
errorJSON
(
err
,
h
.
codec
,
w
)
return
return
...
@@ -218,7 +218,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
...
@@ -218,7 +218,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
out
,
err
:=
storage
.
Delete
(
api
.
WithNamespaceDefaultIfNone
(
ctx
)
,
parts
[
1
])
out
,
err
:=
storage
.
Delete
(
ctx
,
parts
[
1
])
if
err
!=
nil
{
if
err
!=
nil
{
errorJSON
(
err
,
h
.
codec
,
w
)
errorJSON
(
err
,
h
.
codec
,
w
)
return
return
...
@@ -242,7 +242,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
...
@@ -242,7 +242,7 @@ func (h *RESTHandler) handleRESTStorage(parts []string, req *http.Request, w htt
errorJSON
(
err
,
h
.
codec
,
w
)
errorJSON
(
err
,
h
.
codec
,
w
)
return
return
}
}
out
,
err
:=
storage
.
Update
(
api
.
WithNamespaceDefaultIfNone
(
ctx
)
,
obj
)
out
,
err
:=
storage
.
Update
(
ctx
,
obj
)
if
err
!=
nil
{
if
err
!=
nil
{
errorJSON
(
err
,
h
.
codec
,
w
)
errorJSON
(
err
,
h
.
codec
,
w
)
return
return
...
...
pkg/apiserver/watch.go
View file @
7cf66443
...
@@ -77,17 +77,19 @@ func isWebsocketRequest(req *http.Request) bool {
...
@@ -77,17 +77,19 @@ func isWebsocketRequest(req *http.Request) bool {
// ServeHTTP processes watch requests.
// ServeHTTP processes watch requests.
func
(
h
*
WatchHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
func
(
h
*
WatchHandler
)
ServeHTTP
(
w
http
.
ResponseWriter
,
req
*
http
.
Request
)
{
ctx
:=
api
.
NewContext
()
if
req
.
Method
!=
"GET"
{
namespace
:=
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
notFound
(
w
,
req
)
if
len
(
namespace
)
>
0
{
return
ctx
=
api
.
WithNamespace
(
ctx
,
namespace
)
}
}
parts
:=
splitPath
(
req
.
URL
.
Path
)
if
len
(
parts
)
<
1
||
req
.
Method
!=
"GET"
{
namespace
,
kind
,
_
,
err
:=
KindAndNamespace
(
req
)
if
err
!=
nil
{
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
}
}
storage
:=
h
.
storage
[
parts
[
0
]]
ctx
:=
api
.
WithNamespace
(
api
.
NewContext
(),
namespace
)
storage
:=
h
.
storage
[
kind
]
if
storage
==
nil
{
if
storage
==
nil
{
notFound
(
w
,
req
)
notFound
(
w
,
req
)
return
return
...
...
pkg/client/client_test.go
View file @
7cf66443
This diff is collapsed.
Click to expand it.
pkg/client/request.go
View file @
7cf66443
...
@@ -136,7 +136,7 @@ func (r *Request) Namespace(namespace string) *Request {
...
@@ -136,7 +136,7 @@ func (r *Request) Namespace(namespace string) *Request {
return
r
return
r
}
}
if
len
(
namespace
)
>
0
{
if
len
(
namespace
)
>
0
{
return
r
.
setParam
(
"namespace"
,
namespace
)
return
r
.
Path
(
"ns"
)
.
Path
(
namespace
)
}
}
return
r
return
r
}
}
...
...
pkg/controller/replication_controller_test.go
View file @
7cf66443
...
@@ -221,7 +221,7 @@ func TestCreateReplica(t *testing.T) {
...
@@ -221,7 +221,7 @@ func TestCreateReplica(t *testing.T) {
},
},
Spec
:
controllerSpec
.
Spec
.
Template
.
Spec
,
Spec
:
controllerSpec
.
Spec
.
Template
.
Spec
,
}
}
fakeHandler
.
ValidateRequest
(
t
,
makeURL
(
"/
pods?namespace=default
"
),
"POST"
,
nil
)
fakeHandler
.
ValidateRequest
(
t
,
makeURL
(
"/
ns/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
)
...
...
pkg/kubectl/resthelper.go
View file @
7cf66443
...
@@ -47,14 +47,14 @@ func NewRESTHelper(client RESTClient, mapping *meta.RESTMapping) *RESTHelper {
...
@@ -47,14 +47,14 @@ func NewRESTHelper(client RESTClient, mapping *meta.RESTMapping) *RESTHelper {
}
}
func
(
m
*
RESTHelper
)
Get
(
namespace
,
name
string
,
selector
labels
.
Selector
)
(
runtime
.
Object
,
error
)
{
func
(
m
*
RESTHelper
)
Get
(
namespace
,
name
string
,
selector
labels
.
Selector
)
(
runtime
.
Object
,
error
)
{
return
m
.
RESTClient
.
Get
()
.
Path
(
m
.
Resource
)
.
Namespace
(
namespa
ce
)
.
Path
(
name
)
.
SelectorParam
(
"labels"
,
selector
)
.
Do
()
.
Get
()
return
m
.
RESTClient
.
Get
()
.
Namespace
(
namespace
)
.
Path
(
m
.
Resour
ce
)
.
Path
(
name
)
.
SelectorParam
(
"labels"
,
selector
)
.
Do
()
.
Get
()
}
}
func
(
m
*
RESTHelper
)
Watch
(
namespace
,
resourceVersion
string
,
labelSelector
,
fieldSelector
labels
.
Selector
)
(
watch
.
Interface
,
error
)
{
func
(
m
*
RESTHelper
)
Watch
(
namespace
,
resourceVersion
string
,
labelSelector
,
fieldSelector
labels
.
Selector
)
(
watch
.
Interface
,
error
)
{
return
m
.
RESTClient
.
Get
()
.
return
m
.
RESTClient
.
Get
()
.
Path
(
"watch"
)
.
Path
(
"watch"
)
.
Path
(
m
.
Resource
)
.
Namespace
(
namespace
)
.
Namespace
(
namespace
)
.
Path
(
m
.
Resource
)
.
Param
(
"resourceVersion"
,
resourceVersion
)
.
Param
(
"resourceVersion"
,
resourceVersion
)
.
SelectorParam
(
"labels"
,
labelSelector
)
.
SelectorParam
(
"labels"
,
labelSelector
)
.
SelectorParam
(
"fields"
,
fieldSelector
)
.
SelectorParam
(
"fields"
,
fieldSelector
)
.
...
@@ -62,7 +62,7 @@ func (m *RESTHelper) Watch(namespace, resourceVersion string, labelSelector, fie
...
@@ -62,7 +62,7 @@ func (m *RESTHelper) Watch(namespace, resourceVersion string, labelSelector, fie
}
}
func
(
m
*
RESTHelper
)
Delete
(
namespace
,
name
string
)
error
{
func
(
m
*
RESTHelper
)
Delete
(
namespace
,
name
string
)
error
{
return
m
.
RESTClient
.
Delete
()
.
Path
(
m
.
Resource
)
.
Namespace
(
namespa
ce
)
.
Path
(
name
)
.
Do
()
.
Error
()
return
m
.
RESTClient
.
Delete
()
.
Namespace
(
namespace
)
.
Path
(
m
.
Resour
ce
)
.
Path
(
name
)
.
Do
()
.
Error
()
}
}
func
(
m
*
RESTHelper
)
Create
(
namespace
string
,
modify
bool
,
data
[]
byte
)
error
{
func
(
m
*
RESTHelper
)
Create
(
namespace
string
,
modify
bool
,
data
[]
byte
)
error
{
...
@@ -95,7 +95,7 @@ func (m *RESTHelper) Create(namespace string, modify bool, data []byte) error {
...
@@ -95,7 +95,7 @@ func (m *RESTHelper) Create(namespace string, modify bool, data []byte) error {
}
}
func
createResource
(
c
RESTClient
,
resourcePath
,
namespace
string
,
data
[]
byte
)
error
{
func
createResource
(
c
RESTClient
,
resourcePath
,
namespace
string
,
data
[]
byte
)
error
{
return
c
.
Post
()
.
Path
(
resourcePath
)
.
Namespace
(
namespace
)
.
Body
(
data
)
.
Do
()
.
Error
()
return
c
.
Post
()
.
Namespace
(
namespace
)
.
Path
(
resourcePath
)
.
Body
(
data
)
.
Do
()
.
Error
()
}
}
func
(
m
*
RESTHelper
)
Update
(
namespace
,
name
string
,
overwrite
bool
,
data
[]
byte
)
error
{
func
(
m
*
RESTHelper
)
Update
(
namespace
,
name
string
,
overwrite
bool
,
data
[]
byte
)
error
{
...
@@ -138,5 +138,5 @@ func (m *RESTHelper) Update(namespace, name string, overwrite bool, data []byte)
...
@@ -138,5 +138,5 @@ func (m *RESTHelper) Update(namespace, name string, overwrite bool, data []byte)
}
}
func
updateResource
(
c
RESTClient
,
resourcePath
,
namespace
,
name
string
,
data
[]
byte
)
error
{
func
updateResource
(
c
RESTClient
,
resourcePath
,
namespace
,
name
string
,
data
[]
byte
)
error
{
return
c
.
Put
()
.
Path
(
resourcePath
)
.
Namespace
(
namespace
)
.
Path
(
name
)
.
Body
(
data
)
.
Do
()
.
Error
()
return
c
.
Put
()
.
Namespace
(
namespace
)
.
Path
(
resourcePath
)
.
Path
(
name
)
.
Body
(
data
)
.
Do
()
.
Error
()
}
}
pkg/kubectl/resthelper_test.go
View file @
7cf66443
...
@@ -37,6 +37,15 @@ func objBody(obj runtime.Object) io.ReadCloser {
...
@@ -37,6 +37,15 @@ func objBody(obj runtime.Object) io.ReadCloser {
return
ioutil
.
NopCloser
(
bytes
.
NewReader
([]
byte
(
runtime
.
EncodeOrDie
(
testapi
.
Codec
(),
obj
))))
return
ioutil
.
NopCloser
(
bytes
.
NewReader
([]
byte
(
runtime
.
EncodeOrDie
(
testapi
.
Codec
(),
obj
))))
}
}
// splitPath returns the segments for a URL path.
func
splitPath
(
path
string
)
[]
string
{
path
=
strings
.
Trim
(
path
,
"/"
)
if
path
==
""
{
return
[]
string
{}
}
return
strings
.
Split
(
path
,
"/"
)
}
func
TestRESTHelperDelete
(
t
*
testing
.
T
)
{
func
TestRESTHelperDelete
(
t
*
testing
.
T
)
{
tests
:=
[]
struct
{
tests
:=
[]
struct
{
Err
bool
Err
bool
...
@@ -65,12 +74,13 @@ func TestRESTHelperDelete(t *testing.T) {
...
@@ -65,12 +74,13 @@ func TestRESTHelperDelete(t *testing.T) {
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
return
false
return
false
}
}
if
!
strings
.
HasSuffix
(
req
.
URL
.
Path
,
"/foo"
)
{
parts
:=
splitPath
(
req
.
URL
.
Path
)
t
.
Errorf
(
"url doesn't contain name: %#v"
,
req
)
if
parts
[
1
]
!=
"bar"
{
t
.
Errorf
(
"url doesn't contain namespace: %#v"
,
req
)
return
false
return
false
}
}
if
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
!=
"bar
"
{
if
parts
[
2
]
!=
"foo
"
{
t
.
Errorf
(
"url doesn't contain name
space
: %#v"
,
req
)
t
.
Errorf
(
"url doesn't contain name: %#v"
,
req
)
return
false
return
false
}
}
return
true
return
true
...
@@ -105,7 +115,8 @@ func TestRESTHelperCreate(t *testing.T) {
...
@@ -105,7 +115,8 @@ func TestRESTHelperCreate(t *testing.T) {
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
return
false
return
false
}
}
if
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
!=
"bar"
{
parts
:=
splitPath
(
req
.
URL
.
Path
)
if
parts
[
1
]
!=
"bar"
{
t
.
Errorf
(
"url doesn't contain namespace: %#v"
,
req
)
t
.
Errorf
(
"url doesn't contain namespace: %#v"
,
req
)
return
false
return
false
}
}
...
@@ -230,12 +241,13 @@ func TestRESTHelperGet(t *testing.T) {
...
@@ -230,12 +241,13 @@ func TestRESTHelperGet(t *testing.T) {
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
return
false
return
false
}
}
if
!
strings
.
HasSuffix
(
req
.
URL
.
Path
,
"/foo"
)
{
parts
:=
splitPath
(
req
.
URL
.
Path
)
t
.
Errorf
(
"url doesn't contain name: %#v"
,
req
)
if
parts
[
1
]
!=
"bar"
{
t
.
Errorf
(
"url doesn't contain namespace: %#v"
,
req
)
return
false
return
false
}
}
if
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
!=
"bar
"
{
if
parts
[
2
]
!=
"foo
"
{
t
.
Errorf
(
"url doesn't contain name
space
: %#v"
,
req
)
t
.
Errorf
(
"url doesn't contain name: %#v"
,
req
)
return
false
return
false
}
}
return
true
return
true
...
@@ -273,12 +285,13 @@ func TestRESTHelperUpdate(t *testing.T) {
...
@@ -273,12 +285,13 @@ func TestRESTHelperUpdate(t *testing.T) {
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
t
.
Errorf
(
"unexpected method: %#v"
,
req
)
return
false
return
false
}
}
if
!
strings
.
HasSuffix
(
req
.
URL
.
Path
,
"/foo"
)
{
parts
:=
splitPath
(
req
.
URL
.
Path
)
t
.
Errorf
(
"url doesn't contain name: %#v"
,
req
)
if
parts
[
1
]
!=
"bar"
{
t
.
Errorf
(
"url doesn't contain namespace: %#v"
,
req
)
return
false
return
false
}
}
if
req
.
URL
.
Query
()
.
Get
(
"namespace"
)
!=
"bar
"
{
if
parts
[
2
]
!=
"foo
"
{
t
.
Errorf
(
"url doesn't contain name
space
: %#v"
,
req
)
t
.
Errorf
(
"url doesn't contain name: %#v"
,
req
)
return
false
return
false
}
}
return
true
return
true
...
...
plugin/pkg/scheduler/factory/factory_test.go
View file @
7cf66443
...
@@ -192,7 +192,7 @@ func TestDefaultErrorFunc(t *testing.T) {
...
@@ -192,7 +192,7 @@ func TestDefaultErrorFunc(t *testing.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
()
+
"/pods/foo"
,
&
handler
)
mux
.
Handle
(
"/api/"
+
testapi
.
Version
()
+
"/
ns/bar/
pods/foo"
,
&
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 +213,7 @@ func TestDefaultErrorFunc(t *testing.T) {
...
@@ -213,7 +213,7 @@ func TestDefaultErrorFunc(t *testing.T) {
if
!
exists
{
if
!
exists
{
continue
continue
}
}
handler
.
ValidateRequest
(
t
,
"/api/"
+
testapi
.
Version
()
+
"/
pods/foo?namespace=bar
"
,
"GET"
,
nil
)
handler
.
ValidateRequest
(
t
,
"/api/"
+
testapi
.
Version
()
+
"/
ns/bar/pods/foo
"
,
"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
)
}
}
...
...
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