mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-17 15:13:08 +00:00
Add support for Namespace as Kind
Add example for using namespaces
This commit is contained in:
@@ -232,7 +232,7 @@ func (storage *SimpleRESTStorage) Watch(ctx api.Context, label, field labels.Sel
|
||||
storage.requestedLabelSelector = label
|
||||
storage.requestedFieldSelector = field
|
||||
storage.requestedResourceVersion = resourceVersion
|
||||
storage.requestedResourceNamespace = api.Namespace(ctx)
|
||||
storage.requestedResourceNamespace = api.NamespaceValue(ctx)
|
||||
if err := storage.errors["watch"]; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -243,7 +243,7 @@ func (storage *SimpleRESTStorage) Watch(ctx api.Context, label, field labels.Sel
|
||||
// Implement Redirector.
|
||||
func (storage *SimpleRESTStorage) ResourceLocation(ctx api.Context, id string) (string, error) {
|
||||
// validate that the namespace context on the request matches the expected input
|
||||
storage.requestedResourceNamespace = api.Namespace(ctx)
|
||||
storage.requestedResourceNamespace = api.NamespaceValue(ctx)
|
||||
if storage.expectedResourceNamespace != storage.requestedResourceNamespace {
|
||||
return "", fmt.Errorf("Expected request namespace %s, but got namespace %s", storage.expectedResourceNamespace, storage.requestedResourceNamespace)
|
||||
}
|
||||
|
@@ -223,8 +223,10 @@ type APIRequestInfoResolver struct {
|
||||
// GetAPIRequestInfo returns the information from the http request. If error is not nil, APIRequestInfo holds the information as best it is known before the failure
|
||||
// Valid Inputs:
|
||||
// Storage paths
|
||||
// /ns/{namespace}/{resource}
|
||||
// /ns/{namespace}/{resource}/{resourceName}
|
||||
// /namespaces
|
||||
// /namespaces/{namespace}
|
||||
// /namespaces/{namespace}/{resource}
|
||||
// /namespaces/{namespace}/{resource}/{resourceName}
|
||||
// /{resource}
|
||||
// /{resource}/{resourceName}
|
||||
// /{resource}/{resourceName}?namespace={namespace}
|
||||
@@ -287,15 +289,16 @@ func (r *APIRequestInfoResolver) GetAPIRequestInfo(req *http.Request) (APIReques
|
||||
|
||||
}
|
||||
|
||||
// URL forms: /ns/{namespace}/{resource}/*, where parts are adjusted to be relative to kind
|
||||
if currentParts[0] == "ns" {
|
||||
// URL forms: /namespaces/{namespace}/{kind}/*, where parts are adjusted to be relative to kind
|
||||
if currentParts[0] == "namespaces" {
|
||||
if len(currentParts) < 3 {
|
||||
return requestInfo, fmt.Errorf("ResourceTypeAndNamespace expects a path of form /ns/{namespace}/*")
|
||||
requestInfo.Namespace = ""
|
||||
requestInfo.Resource = "namespaces"
|
||||
} else {
|
||||
requestInfo.Resource = currentParts[2]
|
||||
requestInfo.Namespace = currentParts[1]
|
||||
currentParts = currentParts[2:]
|
||||
}
|
||||
requestInfo.Resource = currentParts[2]
|
||||
requestInfo.Namespace = currentParts[1]
|
||||
currentParts = currentParts[2:]
|
||||
|
||||
} else {
|
||||
// URL forms: /{resource}/*
|
||||
// URL forms: POST /{resource} is a legacy API convention to create in "default" namespace
|
||||
|
@@ -77,9 +77,13 @@ func TestGetAPIRequestInfo(t *testing.T) {
|
||||
expectedName string
|
||||
expectedParts []string
|
||||
}{
|
||||
|
||||
// resource paths
|
||||
{"GET", "/ns/other/pods", "list", "", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/ns/other/pods/foo", "get", "", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/namespaces", "list", "", "", "namespaces", "Namespace", "", []string{"namespaces"}},
|
||||
{"GET", "/namespaces/other", "get", "", "", "namespaces", "Namespace", "other", []string{"namespaces", "other"}},
|
||||
|
||||
{"GET", "/namespaces/other/pods", "list", "", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/namespaces/other/pods/foo", "get", "", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/pods", "list", "", api.NamespaceAll, "pods", "Pod", "", []string{"pods"}},
|
||||
{"POST", "/pods", "create", "", api.NamespaceDefault, "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/pods/foo", "get", "", api.NamespaceDefault, "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
@@ -87,16 +91,16 @@ func TestGetAPIRequestInfo(t *testing.T) {
|
||||
{"GET", "/pods?namespace=other", "list", "", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
|
||||
// special verbs
|
||||
{"GET", "/proxy/ns/other/pods/foo", "proxy", "", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/proxy/namespaces/other/pods/foo", "proxy", "", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/proxy/pods/foo", "proxy", "", api.NamespaceDefault, "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/redirect/ns/other/pods/foo", "redirect", "", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/redirect/namespaces/other/pods/foo", "redirect", "", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/redirect/pods/foo", "redirect", "", api.NamespaceDefault, "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/watch/pods", "watch", "", api.NamespaceAll, "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/watch/ns/other/pods", "watch", "", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/watch/namespaces/other/pods", "watch", "", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
|
||||
// fully-qualified paths
|
||||
{"GET", "/api/v1beta1/ns/other/pods", "list", "v1beta1", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/api/v1beta1/ns/other/pods/foo", "get", "v1beta1", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/api/v1beta1/namespaces/other/pods", "list", "v1beta1", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/api/v1beta1/namespaces/other/pods/foo", "get", "v1beta1", "other", "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/api/v1beta1/pods", "list", "v1beta1", api.NamespaceAll, "pods", "Pod", "", []string{"pods"}},
|
||||
{"POST", "/api/v1beta1/pods", "create", "v1beta1", api.NamespaceDefault, "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/api/v1beta1/pods/foo", "get", "v1beta1", api.NamespaceDefault, "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
@@ -105,7 +109,7 @@ func TestGetAPIRequestInfo(t *testing.T) {
|
||||
{"GET", "/api/v1beta1/proxy/pods/foo", "proxy", "v1beta1", api.NamespaceDefault, "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/api/v1beta1/redirect/pods/foo", "redirect", "v1beta1", api.NamespaceDefault, "pods", "Pod", "foo", []string{"pods", "foo"}},
|
||||
{"GET", "/api/v1beta1/watch/pods", "watch", "v1beta1", api.NamespaceAll, "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/api/v1beta1/watch/ns/other/pods", "watch", "v1beta1", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
{"GET", "/api/v1beta1/watch/namespaces/other/pods", "watch", "v1beta1", "other", "pods", "Pod", "", []string{"pods"}},
|
||||
}
|
||||
|
||||
apiRequestInfoResolver := &APIRequestInfoResolver{util.NewStringSet("api"), latest.RESTMapper}
|
||||
@@ -141,11 +145,9 @@ func TestGetAPIRequestInfo(t *testing.T) {
|
||||
}
|
||||
|
||||
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",
|
||||
"no resource path": "/",
|
||||
"just apiversion": "/api/v1beta1/",
|
||||
"apiversion with no resource": "/api/v1beta1/",
|
||||
}
|
||||
for k, v := range errorCases {
|
||||
req, err := http.NewRequest("GET", v, nil)
|
||||
|
@@ -294,7 +294,7 @@ func TestProxy(t *testing.T) {
|
||||
server *httptest.Server
|
||||
proxyTestPattern string
|
||||
}{
|
||||
{namespaceServer, "/prefix/version/proxy/ns/" + item.reqNamespace + "/foo/id" + item.path},
|
||||
{namespaceServer, "/prefix/version/proxy/namespaces/" + item.reqNamespace + "/foo/id" + item.path},
|
||||
{legacyNamespaceServer, "/prefix/version/proxy/foo/id" + item.path + "?namespace=" + item.reqNamespace},
|
||||
}
|
||||
|
||||
|
@@ -107,7 +107,7 @@ func TestRedirectWithNamespaces(t *testing.T) {
|
||||
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)
|
||||
resp, err := client.Get(server.URL + "/prefix/version/redirect/namespaces/other/foo/" + item.id)
|
||||
if resp == nil {
|
||||
t.Fatalf("Unexpected nil resp")
|
||||
}
|
||||
|
@@ -45,6 +45,7 @@ type RESTHandler struct {
|
||||
func (h *RESTHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
requestInfo, err := h.apiRequestInfoResolver.GetAPIRequestInfo(req)
|
||||
if err != nil {
|
||||
glog.Errorf("Unable to handle request %s %s %v", requestInfo.Namespace, requestInfo.Kind, err)
|
||||
notFound(w, req)
|
||||
return
|
||||
}
|
||||
|
Reference in New Issue
Block a user