mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Add verbs to APIResource for discovery
This commit is contained in:
parent
7d1a7eae50
commit
0301487de0
@ -25,7 +25,11 @@ limitations under the License.
|
||||
// separate packages.
|
||||
package v1
|
||||
|
||||
import "strings"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TypeMeta describes an individual object in an API response or request
|
||||
// with strings representing the type of the object and its API schema version.
|
||||
@ -403,6 +407,19 @@ type APIResource struct {
|
||||
Namespaced bool `json:"namespaced" protobuf:"varint,2,opt,name=namespaced"`
|
||||
// kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo')
|
||||
Kind string `json:"kind" protobuf:"bytes,3,opt,name=kind"`
|
||||
// verbs is a list of supported kube verbs (this includes get, list, watch, create,
|
||||
// update, patch, delete, deletecollection, and proxy)
|
||||
Verbs Verbs `json:"verbs" protobuf:"bytes,4,opt,name=verbs"`
|
||||
}
|
||||
|
||||
// Verbs masks the value so protobuf can generate
|
||||
//
|
||||
// +protobuf.nullable=true
|
||||
// +protobuf.options.(gogoproto.goproto_stringer)=false
|
||||
type Verbs []string
|
||||
|
||||
func (vs Verbs) String() string {
|
||||
return fmt.Sprintf("%v", []string(vs))
|
||||
}
|
||||
|
||||
// APIResourceList is a list of APIResource, it is used to expose the name of the
|
||||
|
112
pkg/apis/meta/v1/types_test.go
Normal file
112
pkg/apis/meta/v1/types_test.go
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ugorji/go/codec"
|
||||
)
|
||||
|
||||
func TestVerbsMarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input APIResource
|
||||
result string
|
||||
}{
|
||||
{APIResource{}, `{"name":"","namespaced":false,"kind":"","verbs":null}`},
|
||||
{APIResource{Verbs: Verbs([]string{})}, `{"name":"","namespaced":false,"kind":"","verbs":[]}`},
|
||||
{APIResource{Verbs: Verbs([]string{"delete"})}, `{"name":"","namespaced":false,"kind":"","verbs":["delete"]}`},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
result, err := json.Marshal(&c.input)
|
||||
if err != nil {
|
||||
t.Errorf("[%d] Failed to marshal input: '%v': %v", i, c.input, err)
|
||||
}
|
||||
if string(result) != c.result {
|
||||
t.Errorf("[%d] Failed to marshal input: '%v': expected %+v, got %q", i, c.input, c.result, string(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerbsUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result APIResource
|
||||
}{
|
||||
{`{}`, APIResource{}},
|
||||
{`{"verbs":null}`, APIResource{}},
|
||||
{`{"verbs":[]}`, APIResource{Verbs: Verbs([]string{})}},
|
||||
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
var result APIResource
|
||||
if err := codec.NewDecoderBytes([]byte(c.input), new(codec.JsonHandle)).Decode(&result); err != nil {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.result) {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': expected %+v, got %+v", i, c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerbsUgorjiUnmarshalJSON(t *testing.T) {
|
||||
cases := []struct {
|
||||
input string
|
||||
result APIResource
|
||||
}{
|
||||
{`{}`, APIResource{}},
|
||||
{`{"verbs":null}`, APIResource{}},
|
||||
{`{"verbs":[]}`, APIResource{Verbs: Verbs([]string{})}},
|
||||
{`{"verbs":["delete"]}`, APIResource{Verbs: Verbs([]string{"delete"})}},
|
||||
}
|
||||
|
||||
for i, c := range cases {
|
||||
var result APIResource
|
||||
if err := json.Unmarshal([]byte(c.input), &result); err != nil {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': %v", i, c.input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(result, c.result) {
|
||||
t.Errorf("[%d] Failed to unmarshal input '%v': expected %+v, got %+v", i, c.input, c.result, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerbsProto(t *testing.T) {
|
||||
cases := []APIResource{
|
||||
{},
|
||||
{Verbs: Verbs([]string{})},
|
||||
{Verbs: Verbs([]string{"delete"})},
|
||||
}
|
||||
|
||||
for _, input := range cases {
|
||||
data, err := input.Marshal()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal input: '%v': %v", input, err)
|
||||
}
|
||||
resource := APIResource{}
|
||||
if err := resource.Unmarshal(data); err != nil {
|
||||
t.Fatalf("Failed to unmarshal output: '%v': %v", input, err)
|
||||
}
|
||||
if !reflect.DeepEqual(input, resource) {
|
||||
t.Errorf("Marshal->Unmarshal is not idempotent: '%v' vs '%v'", input, resource)
|
||||
}
|
||||
}
|
||||
}
|
@ -62,6 +62,21 @@ type documentable interface {
|
||||
SwaggerDoc() map[string]string
|
||||
}
|
||||
|
||||
// toDiscoveryKubeVerb maps an action.Verb to the logical kube verb, used for discovery
|
||||
var toDiscoveryKubeVerb = map[string]string{
|
||||
"CONNECT": "", // do not list in discovery.
|
||||
"DELETE": "delete",
|
||||
"DELETECOLLECTION": "deletecollection",
|
||||
"GET": "get",
|
||||
"LIST": "list",
|
||||
"PATCH": "patch",
|
||||
"POST": "create",
|
||||
"PROXY": "proxy",
|
||||
"PUT": "update",
|
||||
"WATCH": "watch",
|
||||
"WATCHLIST": "watch",
|
||||
}
|
||||
|
||||
// errEmptyName is returned when API requests do not fill the name section of the path.
|
||||
var errEmptyName = errors.NewBadRequest("name must be provided")
|
||||
|
||||
@ -490,6 +505,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
allMediaTypes := append(mediaTypes, streamMediaTypes...)
|
||||
ws.Produces(allMediaTypes...)
|
||||
|
||||
kubeVerbs := map[string]struct{}{}
|
||||
reqScope := RequestScope{
|
||||
ContextFunc: ctxFn,
|
||||
Serializer: a.group.Serializer,
|
||||
@ -518,6 +534,14 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
namespaced = ""
|
||||
}
|
||||
|
||||
if kubeVerb, found := toDiscoveryKubeVerb[action.Verb]; found {
|
||||
if len(kubeVerb) != 0 {
|
||||
kubeVerbs[kubeVerb] = struct{}{}
|
||||
}
|
||||
} else {
|
||||
return nil, fmt.Errorf("unknown action verb for discovery: %s", action.Verb)
|
||||
}
|
||||
|
||||
switch action.Verb {
|
||||
case "GET": // Get a resource.
|
||||
var handler restful.RouteFunction
|
||||
@ -754,6 +778,13 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
|
||||
}
|
||||
// Note: update GetAuthorizerAttributes() when adding a custom handler.
|
||||
}
|
||||
|
||||
apiResource.Verbs = make([]string, 0, len(kubeVerbs))
|
||||
for kubeVerb := range kubeVerbs {
|
||||
apiResource.Verbs = append(apiResource.Verbs, kubeVerb)
|
||||
}
|
||||
sort.Strings(apiResource.Verbs)
|
||||
|
||||
return &apiResource, nil
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ type Attributes interface {
|
||||
// GetUser returns the user.Info object to authorize
|
||||
GetUser() user.Info
|
||||
|
||||
// GetVerb returns the kube verb associated with API requests (this includes get, list, watch, create, update, patch, delete, and proxy),
|
||||
// GetVerb returns the kube verb associated with API requests (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy),
|
||||
// or the lowercased HTTP verb associated with non-API requests (this includes get, put, post, patch, and delete)
|
||||
GetVerb() string
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user