Merge pull request #44787 from mbohlool/c1

Automatic merge from submit-queue (batch tested with PRs 45684, 45266, 45669, 44787, 44984)

Add GroupVersionKind extension to OpenAPI operations

Fixes: #43249
ref: #34254

```release-note
Added Group/Version/Kind and Action extension to OpenAPI Operations 
```
This commit is contained in:
Kubernetes Submit Queue 2017-05-12 03:20:42 -07:00 committed by GitHub
commit d437703d27
4 changed files with 4565 additions and 20 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -42,6 +42,11 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
) )
const (
ROUTE_META_GVK = "x-kubernetes-group-version-kind"
ROUTE_META_ACTION = "x-kubernetes-action"
)
type APIInstaller struct { type APIInstaller struct {
group *APIGroupVersion group *APIGroupVersion
prefix string // Path prefix where API resources are to be registered. prefix string // Path prefix where API resources are to be registered.
@ -557,6 +562,8 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
return nil, fmt.Errorf("unknown action verb for discovery: %s", action.Verb) return nil, fmt.Errorf("unknown action verb for discovery: %s", action.Verb)
} }
routes := []*restful.RouteBuilder{}
switch action.Verb { switch action.Verb {
case "GET": // Get a resource. case "GET": // Get a resource.
var handler restful.RouteFunction var handler restful.RouteFunction
@ -588,7 +595,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
} }
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
case "LIST": // List all resources of a kind. case "LIST": // List all resources of a kind.
doc := "list objects of kind " + kind doc := "list objects of kind " + kind
if hasSubresource { if hasSubresource {
@ -620,7 +627,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
route.Doc(doc) route.Doc(doc)
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
case "PUT": // Update a resource. case "PUT": // Update a resource.
doc := "replace the specified " + kind doc := "replace the specified " + kind
if hasSubresource { if hasSubresource {
@ -636,7 +643,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
Reads(versionedObject). Reads(versionedObject).
Writes(versionedObject) Writes(versionedObject)
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
case "PATCH": // Partially update a resource case "PATCH": // Partially update a resource
doc := "partially update the specified " + kind doc := "partially update the specified " + kind
if hasSubresource { if hasSubresource {
@ -653,7 +660,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
Reads(metav1.Patch{}). Reads(metav1.Patch{}).
Writes(versionedObject) Writes(versionedObject)
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
case "POST": // Create a resource. case "POST": // Create a resource.
var handler restful.RouteFunction var handler restful.RouteFunction
if isNamedCreater { if isNamedCreater {
@ -676,7 +683,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
Reads(versionedObject). Reads(versionedObject).
Writes(versionedObject) Writes(versionedObject)
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
case "DELETE": // Delete a resource. case "DELETE": // Delete a resource.
article := getArticleForNoun(kind, " ") article := getArticleForNoun(kind, " ")
doc := "delete" + article + kind doc := "delete" + article + kind
@ -698,7 +705,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
} }
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
case "DELETECOLLECTION": case "DELETECOLLECTION":
doc := "delete collection of " + kind doc := "delete collection of " + kind
if hasSubresource { if hasSubresource {
@ -716,7 +723,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
return nil, err return nil, err
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
// TODO: deprecated // TODO: deprecated
case "WATCH": // Watch a resource. case "WATCH": // Watch a resource.
doc := "watch changes to an object of kind " + kind doc := "watch changes to an object of kind " + kind
@ -735,7 +742,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
return nil, err return nil, err
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
// TODO: deprecated // TODO: deprecated
case "WATCHLIST": // Watch all resources of a kind. case "WATCHLIST": // Watch all resources of a kind.
doc := "watch individual changes to a list of " + kind doc := "watch individual changes to a list of " + kind
@ -754,19 +761,19 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
return nil, err return nil, err
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
// We add "proxy" subresource to remove the need for the generic top level prefix proxy. // We add "proxy" subresource to remove the need for the generic top level prefix proxy.
// The generic top level prefix proxy is deprecated in v1.2, and will be removed in 1.3, or 1.4 at the latest. // The generic top level prefix proxy is deprecated in v1.2, and will be removed in 1.3, or 1.4 at the latest.
// TODO: DEPRECATED in v1.2. // TODO: DEPRECATED in v1.2.
case "PROXY": // Proxy requests to a resource. case "PROXY": // Proxy requests to a resource.
// Accept all methods as per http://issue.k8s.io/3996 // Accept all methods as per http://issue.k8s.io/3996
addProxyRoute(ws, "GET", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "GET", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
addProxyRoute(ws, "PUT", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "PUT", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
addProxyRoute(ws, "POST", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "POST", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
addProxyRoute(ws, "PATCH", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "PATCH", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
addProxyRoute(ws, "DELETE", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "DELETE", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
addProxyRoute(ws, "HEAD", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "HEAD", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
addProxyRoute(ws, "OPTIONS", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix) routes = append(routes, buildProxyRoute(ws, "OPTIONS", a.prefix, action.Path, proxyHandler, namespaced, kind, resource, subresource, hasSubresource, action.Params, operationSuffix))
case "CONNECT": case "CONNECT":
for _, method := range connecter.ConnectMethods() { for _, method := range connecter.ConnectMethods() {
doc := "connect " + method + " requests to " + kind doc := "connect " + method + " requests to " + kind
@ -787,11 +794,16 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
} }
} }
addParams(route, action.Params) addParams(route, action.Params)
ws.Route(route) routes = append(routes, route)
} }
default: default:
return nil, fmt.Errorf("unrecognized action verb: %s", action.Verb) return nil, fmt.Errorf("unrecognized action verb: %s", action.Verb)
} }
for _, route := range routes {
route.Metadata(ROUTE_META_GVK, reqScope.Kind)
route.Metadata(ROUTE_META_ACTION, action.Verb)
ws.Route(route)
}
// Note: update GetAuthorizerAttributes() when adding a custom handler. // Note: update GetAuthorizerAttributes() when adding a custom handler.
} }
@ -824,7 +836,7 @@ func routeFunction(handler http.Handler) restful.RouteFunction {
} }
} }
func addProxyRoute(ws *restful.WebService, method string, prefix string, path string, proxyHandler http.Handler, namespaced, kind, resource, subresource string, hasSubresource bool, params []*restful.Parameter, operationSuffix string) { func buildProxyRoute(ws *restful.WebService, method string, prefix string, path string, proxyHandler http.Handler, namespaced, kind, resource, subresource string, hasSubresource bool, params []*restful.Parameter, operationSuffix string) *restful.RouteBuilder {
doc := "proxy " + method + " requests to " + kind doc := "proxy " + method + " requests to " + kind
if hasSubresource { if hasSubresource {
doc = "proxy " + method + " requests to " + subresource + " of " + kind doc = "proxy " + method + " requests to " + subresource + " of " + kind
@ -837,7 +849,7 @@ func addProxyRoute(ws *restful.WebService, method string, prefix string, path st
Consumes("*/*"). Consumes("*/*").
Writes("string") Writes("string")
addParams(proxyRoute, params) addParams(proxyRoute, params)
ws.Route(proxyRoute) return proxyRoute
} }
func addParams(route *restful.RouteBuilder, params []*restful.Parameter) { func addParams(route *restful.RouteBuilder, params []*restful.Parameter) {

View File

@ -32,7 +32,8 @@ import (
) )
const ( const (
OpenAPIVersion = "2.0" OpenAPIVersion = "2.0"
extensionPrefix = "x-kubernetes-"
) )
type openAPI struct { type openAPI struct {
@ -259,6 +260,14 @@ func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map
}, },
}, },
} }
for k, v := range route.Metadata {
if strings.HasPrefix(k, extensionPrefix) {
if ret.Extensions == nil {
ret.Extensions = spec.Extensions{}
}
ret.Extensions.Add(k, v)
}
}
if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTags(o.servePath, &route); err != nil { if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTags(o.servePath, &route); err != nil {
return ret, err return ret, err
} }