mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-14 02:43:36 +00:00
rebase: update replaced k8s.io modules to v0.33.0
Signed-off-by: Niels de Vos <ndevos@ibm.com>
This commit is contained in:
committed by
mergify[bot]
parent
dd77e72800
commit
107407b44b
20
e2e/vendor/k8s.io/kube-openapi/pkg/builder/doc.go
generated
vendored
20
e2e/vendor/k8s.io/kube-openapi/pkg/builder/doc.go
generated
vendored
@ -1,20 +0,0 @@
|
||||
/*
|
||||
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 builder contains code to generate OpenAPI discovery spec (which
|
||||
// initial version of it also known as Swagger 2.0).
|
||||
// For more details: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md
|
||||
package builder
|
468
e2e/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
generated
vendored
468
e2e/vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
generated
vendored
@ -1,468 +0,0 @@
|
||||
/*
|
||||
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 builder
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
restful "github.com/emicklei/go-restful/v3"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/common/restfuladapter"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
OpenAPIVersion = "2.0"
|
||||
)
|
||||
|
||||
type openAPI struct {
|
||||
config *common.Config
|
||||
swagger *spec.Swagger
|
||||
protocolList []string
|
||||
definitions map[string]common.OpenAPIDefinition
|
||||
}
|
||||
|
||||
// BuildOpenAPISpec builds OpenAPI spec given a list of route containers and common.Config to customize it.
|
||||
//
|
||||
// Deprecated: BuildOpenAPISpecFromRoutes should be used instead.
|
||||
func BuildOpenAPISpec(routeContainers []*restful.WebService, config *common.Config) (*spec.Swagger, error) {
|
||||
return BuildOpenAPISpecFromRoutes(restfuladapter.AdaptWebServices(routeContainers), config)
|
||||
}
|
||||
|
||||
// BuildOpenAPISpecFromRoutes builds OpenAPI spec given a list of route containers and common.Config to customize it.
|
||||
func BuildOpenAPISpecFromRoutes(routeContainers []common.RouteContainer, config *common.Config) (*spec.Swagger, error) {
|
||||
o := newOpenAPI(config)
|
||||
err := o.buildPaths(routeContainers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return o.finalizeSwagger()
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it.
|
||||
func BuildOpenAPIDefinitionsForResource(model interface{}, config *common.Config) (*spec.Definitions, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
_, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
swagger, err := o.finalizeSwagger()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &swagger.Definitions, nil
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResources returns the OpenAPI spec which includes the definitions for the
|
||||
// passed type names.
|
||||
func BuildOpenAPIDefinitionsForResources(config *common.Config, names ...string) (*spec.Swagger, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
for _, name := range names {
|
||||
_, err := o.toSchema(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return o.finalizeSwagger()
|
||||
}
|
||||
|
||||
// newOpenAPI sets up the openAPI object so we can build the spec.
|
||||
func newOpenAPI(config *common.Config) openAPI {
|
||||
o := openAPI{
|
||||
config: config,
|
||||
swagger: &spec.Swagger{
|
||||
SwaggerProps: spec.SwaggerProps{
|
||||
Swagger: OpenAPIVersion,
|
||||
Definitions: spec.Definitions{},
|
||||
Responses: config.ResponseDefinitions,
|
||||
Paths: &spec.Paths{Paths: map[string]spec.PathItem{}},
|
||||
Info: config.Info,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if o.config.GetOperationIDAndTagsFromRoute == nil {
|
||||
// Map the deprecated handler to the common interface, if provided.
|
||||
if o.config.GetOperationIDAndTags != nil {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
restfulRouteAdapter, ok := r.(*restfuladapter.RouteAdapter)
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("config.GetOperationIDAndTags specified but route is not a restful v1 Route")
|
||||
}
|
||||
|
||||
return o.config.GetOperationIDAndTags(restfulRouteAdapter.Route)
|
||||
}
|
||||
} else {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
return r.OperationName(), nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.config.GetDefinitionName == nil {
|
||||
o.config.GetDefinitionName = func(name string) (string, spec.Extensions) {
|
||||
return name[strings.LastIndex(name, "/")+1:], nil
|
||||
}
|
||||
}
|
||||
o.definitions = o.config.GetDefinitions(func(name string) spec.Ref {
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return spec.MustCreateRef("#/definitions/" + common.EscapeJsonPointer(defName))
|
||||
})
|
||||
if o.config.CommonResponses == nil {
|
||||
o.config.CommonResponses = map[int]spec.Response{}
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
// finalizeSwagger is called after the spec is built and returns the final spec.
|
||||
// NOTE: finalizeSwagger also make changes to the final spec, as specified in the config.
|
||||
func (o *openAPI) finalizeSwagger() (*spec.Swagger, error) {
|
||||
if o.config.SecurityDefinitions != nil {
|
||||
o.swagger.SecurityDefinitions = *o.config.SecurityDefinitions
|
||||
o.swagger.Security = o.config.DefaultSecurity
|
||||
}
|
||||
if o.config.PostProcessSpec != nil {
|
||||
var err error
|
||||
o.swagger, err = o.config.PostProcessSpec(o.swagger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return deduplicateParameters(o.swagger)
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionRecursively(name string) error {
|
||||
uniqueName, extensions := o.config.GetDefinitionName(name)
|
||||
if _, ok := o.swagger.Definitions[uniqueName]; ok {
|
||||
return nil
|
||||
}
|
||||
if item, ok := o.definitions[name]; ok {
|
||||
schema := spec.Schema{
|
||||
VendorExtensible: item.Schema.VendorExtensible,
|
||||
SchemaProps: item.Schema.SchemaProps,
|
||||
SwaggerSchemaProps: item.Schema.SwaggerSchemaProps,
|
||||
}
|
||||
if extensions != nil {
|
||||
if schema.Extensions == nil {
|
||||
schema.Extensions = spec.Extensions{}
|
||||
}
|
||||
for k, v := range extensions {
|
||||
schema.Extensions[k] = v
|
||||
}
|
||||
}
|
||||
if v, ok := item.Schema.Extensions[common.ExtensionV2Schema]; ok {
|
||||
if v2Schema, isOpenAPISchema := v.(spec.Schema); isOpenAPISchema {
|
||||
schema = v2Schema
|
||||
}
|
||||
}
|
||||
o.swagger.Definitions[uniqueName] = schema
|
||||
for _, v := range item.Dependencies {
|
||||
if err := o.buildDefinitionRecursively(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("cannot find model definition for %v. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildDefinitionForType build a definition for a given type and return a referable name to its definition.
|
||||
// This is the main function that keep track of definitions used in this spec and is depend on code generated
|
||||
// by k8s.io/kubernetes/cmd/libs/go2idl/openapi-gen.
|
||||
func (o *openAPI) buildDefinitionForType(name string) (string, error) {
|
||||
if err := o.buildDefinitionRecursively(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return "#/definitions/" + common.EscapeJsonPointer(defName), nil
|
||||
}
|
||||
|
||||
// buildPaths builds OpenAPI paths using go-restful's web services.
|
||||
func (o *openAPI) buildPaths(routeContainers []common.RouteContainer) error {
|
||||
pathsToIgnore := util.NewTrie(o.config.IgnorePrefixes)
|
||||
duplicateOpId := make(map[string]string)
|
||||
for _, w := range routeContainers {
|
||||
rootPath := w.RootPath()
|
||||
if pathsToIgnore.HasPrefix(rootPath) {
|
||||
continue
|
||||
}
|
||||
commonParams, err := o.buildParameters(w.PathParameters())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for path, routes := range groupRoutesByPath(w.Routes()) {
|
||||
// go-swagger has special variable definition {$NAME:*} that can only be
|
||||
// used at the end of the path and it is not recognized by OpenAPI.
|
||||
if strings.HasSuffix(path, ":*}") {
|
||||
path = path[:len(path)-3] + "}"
|
||||
}
|
||||
if pathsToIgnore.HasPrefix(path) {
|
||||
continue
|
||||
}
|
||||
// Aggregating common parameters make API spec (and generated clients) simpler
|
||||
inPathCommonParamsMap, err := o.findCommonParameters(routes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathItem, exists := o.swagger.Paths.Paths[path]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate webservice route has been found for path: %v", path)
|
||||
}
|
||||
pathItem = spec.PathItem{
|
||||
PathItemProps: spec.PathItemProps{
|
||||
Parameters: make([]spec.Parameter, 0),
|
||||
},
|
||||
}
|
||||
// add web services's parameters as well as any parameters appears in all ops, as common parameters
|
||||
pathItem.Parameters = append(pathItem.Parameters, commonParams...)
|
||||
for _, p := range inPathCommonParamsMap {
|
||||
pathItem.Parameters = append(pathItem.Parameters, p)
|
||||
}
|
||||
sortParameters(pathItem.Parameters)
|
||||
for _, route := range routes {
|
||||
op, err := o.buildOperations(route, inPathCommonParamsMap)
|
||||
sortParameters(op.Parameters)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dpath, exists := duplicateOpId[op.ID]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate Operation ID %v for path %v and %v", op.ID, dpath, path)
|
||||
} else {
|
||||
duplicateOpId[op.ID] = path
|
||||
}
|
||||
switch strings.ToUpper(route.Method()) {
|
||||
case "GET":
|
||||
pathItem.Get = op
|
||||
case "POST":
|
||||
pathItem.Post = op
|
||||
case "HEAD":
|
||||
pathItem.Head = op
|
||||
case "PUT":
|
||||
pathItem.Put = op
|
||||
case "DELETE":
|
||||
pathItem.Delete = op
|
||||
case "OPTIONS":
|
||||
pathItem.Options = op
|
||||
case "PATCH":
|
||||
pathItem.Patch = op
|
||||
}
|
||||
}
|
||||
o.swagger.Paths.Paths[path] = pathItem
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// buildOperations builds operations for each webservice path
|
||||
func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[interface{}]spec.Parameter) (ret *spec.Operation, err error) {
|
||||
ret = &spec.Operation{
|
||||
OperationProps: spec.OperationProps{
|
||||
Description: route.Description(),
|
||||
Consumes: route.Consumes(),
|
||||
Produces: route.Produces(),
|
||||
Schemes: o.config.ProtocolList,
|
||||
Responses: &spec.Responses{
|
||||
ResponsesProps: spec.ResponsesProps{
|
||||
StatusCodeResponses: make(map[int]spec.Response),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range route.Metadata() {
|
||||
if strings.HasPrefix(k, common.ExtensionPrefix) {
|
||||
if ret.Extensions == nil {
|
||||
ret.Extensions = spec.Extensions{}
|
||||
}
|
||||
ret.Extensions.Add(k, v)
|
||||
}
|
||||
}
|
||||
if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTagsFromRoute(route); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Build responses
|
||||
for _, resp := range route.StatusCodeResponses() {
|
||||
ret.Responses.StatusCodeResponses[resp.Code()], err = o.buildResponse(resp.Model(), resp.Message())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
// If there is no response but a write sample, assume that write sample is an http.StatusOK response.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 && route.ResponsePayloadSample() != nil {
|
||||
ret.Responses.StatusCodeResponses[http.StatusOK], err = o.buildResponse(route.ResponsePayloadSample(), "OK")
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
for code, resp := range o.config.CommonResponses {
|
||||
if _, exists := ret.Responses.StatusCodeResponses[code]; !exists {
|
||||
ret.Responses.StatusCodeResponses[code] = resp
|
||||
}
|
||||
}
|
||||
// If there is still no response, use default response provided.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 {
|
||||
ret.Responses.Default = o.config.DefaultResponse
|
||||
}
|
||||
|
||||
// Build non-common Parameters
|
||||
ret.Parameters = make([]spec.Parameter, 0)
|
||||
for _, param := range route.Parameters() {
|
||||
if _, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]; !isCommon {
|
||||
openAPIParam, err := o.buildParameter(param, route.RequestPayloadSample())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
ret.Parameters = append(ret.Parameters, openAPIParam)
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildResponse(model interface{}, description string) (spec.Response, error) {
|
||||
schema, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return spec.Response{}, err
|
||||
}
|
||||
return spec.Response{
|
||||
ResponseProps: spec.ResponseProps{
|
||||
Description: description,
|
||||
Schema: schema,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) findCommonParameters(routes []common.Route) (map[interface{}]spec.Parameter, error) {
|
||||
commonParamsMap := make(map[interface{}]spec.Parameter, 0)
|
||||
paramOpsCountByName := make(map[interface{}]int, 0)
|
||||
paramNameKindToDataMap := make(map[interface{}]common.Parameter, 0)
|
||||
for _, route := range routes {
|
||||
routeParamDuplicateMap := make(map[interface{}]bool)
|
||||
s := ""
|
||||
params := route.Parameters()
|
||||
for _, param := range params {
|
||||
m, _ := json.Marshal(param)
|
||||
s += string(m) + "\n"
|
||||
key := mapKeyFromParam(param)
|
||||
if routeParamDuplicateMap[key] {
|
||||
msg, _ := json.Marshal(params)
|
||||
return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v", param.Name(), string(msg), s)
|
||||
}
|
||||
routeParamDuplicateMap[key] = true
|
||||
paramOpsCountByName[key]++
|
||||
paramNameKindToDataMap[key] = param
|
||||
}
|
||||
}
|
||||
for key, count := range paramOpsCountByName {
|
||||
paramData := paramNameKindToDataMap[key]
|
||||
if count == len(routes) && paramData.Kind() != common.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(paramData, nil)
|
||||
if err != nil {
|
||||
return commonParamsMap, err
|
||||
}
|
||||
commonParamsMap[key] = openAPIParam
|
||||
}
|
||||
}
|
||||
return commonParamsMap, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) toSchema(name string) (_ *spec.Schema, err error) {
|
||||
if openAPIType, openAPIFormat := common.OpenAPITypeFormat(name); openAPIType != "" {
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
ref, err := o.buildDefinitionForType(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: spec.MustCreateRef(ref),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameter(restParam common.Parameter, bodySample interface{}) (ret spec.Parameter, err error) {
|
||||
ret = spec.Parameter{
|
||||
ParamProps: spec.ParamProps{
|
||||
Name: restParam.Name(),
|
||||
Description: restParam.Description(),
|
||||
Required: restParam.Required(),
|
||||
},
|
||||
}
|
||||
switch restParam.Kind() {
|
||||
case common.BodyParameterKind:
|
||||
if bodySample != nil {
|
||||
ret.In = "body"
|
||||
ret.Schema, err = o.toSchema(util.GetCanonicalTypeName(bodySample))
|
||||
return ret, err
|
||||
} else {
|
||||
// There is not enough information in the body parameter to build the definition.
|
||||
// Body parameter has a data type that is a short name but we need full package name
|
||||
// of the type to create a definition.
|
||||
return ret, fmt.Errorf("restful body parameters are not supported: %v", restParam.DataType())
|
||||
}
|
||||
case common.PathParameterKind:
|
||||
ret.In = "path"
|
||||
if !restParam.Required() {
|
||||
return ret, fmt.Errorf("path parameters should be marked at required for parameter %v", restParam)
|
||||
}
|
||||
case common.QueryParameterKind:
|
||||
ret.In = "query"
|
||||
case common.HeaderParameterKind:
|
||||
ret.In = "header"
|
||||
case common.FormParameterKind:
|
||||
ret.In = "formData"
|
||||
default:
|
||||
return ret, fmt.Errorf("unknown restful operation kind : %v", restParam.Kind())
|
||||
}
|
||||
openAPIType, openAPIFormat := common.OpenAPITypeFormat(restParam.DataType())
|
||||
if openAPIType == "" {
|
||||
return ret, fmt.Errorf("non-body Restful parameter type should be a simple type, but got : %v", restParam.DataType())
|
||||
}
|
||||
ret.Type = openAPIType
|
||||
ret.Format = openAPIFormat
|
||||
ret.UniqueItems = !restParam.AllowMultiple()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameters(restParam []common.Parameter) (ret []spec.Parameter, err error) {
|
||||
ret = make([]spec.Parameter, len(restParam))
|
||||
for i, v := range restParam {
|
||||
ret[i], err = o.buildParameter(v, nil)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
259
e2e/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go
generated
vendored
259
e2e/vendor/k8s.io/kube-openapi/pkg/builder/parameters.go
generated
vendored
@ -1,259 +0,0 @@
|
||||
/*
|
||||
Copyright 2023 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 builder
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// deduplicateParameters finds parameters that are shared across multiple endpoints and replace them with
|
||||
// references to the shared parameters in order to avoid repetition.
|
||||
//
|
||||
// deduplicateParameters does not mutate the source.
|
||||
func deduplicateParameters(sp *spec.Swagger) (*spec.Swagger, error) {
|
||||
names, parameters, err := collectSharedParameters(sp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if sp.Parameters != nil {
|
||||
return nil, fmt.Errorf("shared parameters already exist") // should not happen with the builder, but to be sure
|
||||
}
|
||||
|
||||
clone := *sp
|
||||
clone.Parameters = parameters
|
||||
return replaceSharedParameters(names, &clone)
|
||||
}
|
||||
|
||||
// collectSharedParameters finds parameters that show up for many endpoints. These
|
||||
// are basically all parameters with the exceptions of those where we know they are
|
||||
// endpoint specific, e.g. because they reference the schema of the kind, or have
|
||||
// the kind or resource name in the description.
|
||||
func collectSharedParameters(sp *spec.Swagger) (namesByJSON map[string]string, ret map[string]spec.Parameter, err error) {
|
||||
if sp == nil || sp.Paths == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
countsByJSON := map[string]int{}
|
||||
shared := map[string]spec.Parameter{}
|
||||
var keys []string
|
||||
|
||||
collect := func(p *spec.Parameter) error {
|
||||
if (p.In == "query" || p.In == "path") && p.Name == "name" {
|
||||
return nil // ignore name parameter as they are never shared with the Kind in the description
|
||||
}
|
||||
if p.In == "query" && p.Name == "fieldValidation" {
|
||||
return nil // keep fieldValidation parameter unshared because kubectl uses it (until 1.27) to detect server-side field validation support
|
||||
}
|
||||
if p.In == "query" && p.Name == "dryRun" {
|
||||
return nil // keep fieldValidation parameter unshared because kubectl uses it (until 1.26) to detect dry-run support
|
||||
}
|
||||
if p.Schema != nil && p.In == "body" && p.Name == "body" && !strings.HasPrefix(p.Schema.Ref.String(), "#/definitions/io.k8s.apimachinery") {
|
||||
return nil // ignore non-generic body parameters as they reference the custom schema of the kind
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
k := string(bs)
|
||||
countsByJSON[k]++
|
||||
if count := countsByJSON[k]; count == 1 {
|
||||
shared[k] = *p
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, path := range sp.Paths.Paths {
|
||||
// per operation parameters
|
||||
for _, op := range operations(&path) {
|
||||
if op == nil {
|
||||
continue // shouldn't happen, but ignore if it does; tested through unit test
|
||||
}
|
||||
for _, p := range op.Parameters {
|
||||
if p.Ref.String() != "" {
|
||||
// shouldn't happen, but ignore if it does
|
||||
continue
|
||||
}
|
||||
if err := collect(&p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// per path parameters
|
||||
for _, p := range path.Parameters {
|
||||
if p.Ref.String() != "" {
|
||||
continue // shouldn't happen, but ignore if it does
|
||||
}
|
||||
if err := collect(&p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// name deterministically
|
||||
sort.Strings(keys)
|
||||
ret = map[string]spec.Parameter{}
|
||||
namesByJSON = map[string]string{}
|
||||
for _, k := range keys {
|
||||
name := shared[k].Name
|
||||
if name == "" {
|
||||
// this should never happen as the name is a required field. But if it does, let's be safe.
|
||||
name = "param"
|
||||
}
|
||||
name += "-" + base64Hash(k)
|
||||
i := 0
|
||||
for {
|
||||
if _, ok := ret[name]; !ok {
|
||||
ret[name] = shared[k]
|
||||
namesByJSON[k] = name
|
||||
break
|
||||
}
|
||||
i++ // only on hash conflict, unlikely with our few variants
|
||||
name = shared[k].Name + "-" + strconv.Itoa(i)
|
||||
}
|
||||
}
|
||||
|
||||
return namesByJSON, ret, nil
|
||||
}
|
||||
|
||||
func operations(path *spec.PathItem) []*spec.Operation {
|
||||
return []*spec.Operation{path.Get, path.Put, path.Post, path.Delete, path.Options, path.Head, path.Patch}
|
||||
}
|
||||
|
||||
func base64Hash(s string) string {
|
||||
hash := fnv.New64()
|
||||
hash.Write([]byte(s)) //nolint:errcheck
|
||||
return base64.URLEncoding.EncodeToString(hash.Sum(make([]byte, 0, 8))[:6]) // 8 characters
|
||||
}
|
||||
|
||||
func replaceSharedParameters(sharedParameterNamesByJSON map[string]string, sp *spec.Swagger) (*spec.Swagger, error) {
|
||||
if sp == nil || sp.Paths == nil {
|
||||
return sp, nil
|
||||
}
|
||||
|
||||
ret := sp
|
||||
|
||||
firstPathChange := true
|
||||
for k, path := range sp.Paths.Paths {
|
||||
pathChanged := false
|
||||
|
||||
// per operation parameters
|
||||
for _, op := range []**spec.Operation{&path.Get, &path.Put, &path.Post, &path.Delete, &path.Options, &path.Head, &path.Patch} {
|
||||
if *op == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
firstParamChange := true
|
||||
for i := range (*op).Parameters {
|
||||
p := (*op).Parameters[i]
|
||||
|
||||
if p.Ref.String() != "" {
|
||||
// shouldn't happen, but be idem-potent if it does
|
||||
continue
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if name, ok := sharedParameterNamesByJSON[string(bs)]; ok {
|
||||
if firstParamChange {
|
||||
orig := *op
|
||||
*op = &spec.Operation{}
|
||||
**op = *orig
|
||||
(*op).Parameters = make([]spec.Parameter, len(orig.Parameters))
|
||||
copy((*op).Parameters, orig.Parameters)
|
||||
firstParamChange = false
|
||||
}
|
||||
|
||||
(*op).Parameters[i] = spec.Parameter{
|
||||
Refable: spec.Refable{
|
||||
Ref: spec.MustCreateRef("#/parameters/" + name),
|
||||
},
|
||||
}
|
||||
pathChanged = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// per path parameters
|
||||
firstParamChange := true
|
||||
for i := range path.Parameters {
|
||||
p := path.Parameters[i]
|
||||
|
||||
if p.Ref.String() != "" {
|
||||
// shouldn't happen, but be idem-potent if it does
|
||||
continue
|
||||
}
|
||||
|
||||
bs, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if name, ok := sharedParameterNamesByJSON[string(bs)]; ok {
|
||||
if firstParamChange {
|
||||
orig := path.Parameters
|
||||
path.Parameters = make([]spec.Parameter, len(orig))
|
||||
copy(path.Parameters, orig)
|
||||
firstParamChange = false
|
||||
}
|
||||
|
||||
path.Parameters[i] = spec.Parameter{
|
||||
Refable: spec.Refable{
|
||||
Ref: spec.MustCreateRef("#/parameters/" + name),
|
||||
},
|
||||
}
|
||||
pathChanged = true
|
||||
}
|
||||
}
|
||||
|
||||
if pathChanged {
|
||||
if firstPathChange {
|
||||
clone := *sp
|
||||
ret = &clone
|
||||
|
||||
pathsClone := *ret.Paths
|
||||
ret.Paths = &pathsClone
|
||||
|
||||
ret.Paths.Paths = make(map[string]spec.PathItem, len(sp.Paths.Paths))
|
||||
for k, v := range sp.Paths.Paths {
|
||||
ret.Paths.Paths[k] = v
|
||||
}
|
||||
|
||||
firstPathChange = false
|
||||
}
|
||||
ret.Paths.Paths[k] = path
|
||||
}
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
61
e2e/vendor/k8s.io/kube-openapi/pkg/builder/util.go
generated
vendored
61
e2e/vendor/k8s.io/kube-openapi/pkg/builder/util.go
generated
vendored
@ -1,61 +0,0 @@
|
||||
/*
|
||||
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 builder
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
type parameters []spec.Parameter
|
||||
|
||||
func (s parameters) Len() int { return len(s) }
|
||||
func (s parameters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
// byNameIn used in sorting parameters by Name and In fields.
|
||||
type byNameIn struct {
|
||||
parameters
|
||||
}
|
||||
|
||||
func (s byNameIn) Less(i, j int) bool {
|
||||
return s.parameters[i].Name < s.parameters[j].Name || (s.parameters[i].Name == s.parameters[j].Name && s.parameters[i].In < s.parameters[j].In)
|
||||
}
|
||||
|
||||
// SortParameters sorts parameters by Name and In fields.
|
||||
func sortParameters(p []spec.Parameter) {
|
||||
sort.Sort(byNameIn{p})
|
||||
}
|
||||
|
||||
func groupRoutesByPath(routes []common.Route) map[string][]common.Route {
|
||||
pathToRoutes := make(map[string][]common.Route)
|
||||
for _, r := range routes {
|
||||
pathToRoutes[r.Path()] = append(pathToRoutes[r.Path()], r)
|
||||
}
|
||||
return pathToRoutes
|
||||
}
|
||||
|
||||
func mapKeyFromParam(param common.Parameter) interface{} {
|
||||
return struct {
|
||||
Name string
|
||||
Kind common.ParameterKind
|
||||
}{
|
||||
Name: param.Name(),
|
||||
Kind: param.Kind(),
|
||||
}
|
||||
}
|
498
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go
generated
vendored
498
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/openapi.go
generated
vendored
@ -1,498 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 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 builder3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
restful "github.com/emicklei/go-restful/v3"
|
||||
|
||||
builderutil "k8s.io/kube-openapi/pkg/builder3/util"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/common/restfuladapter"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/util"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
OpenAPIVersion = "3.0"
|
||||
)
|
||||
|
||||
type openAPI struct {
|
||||
config *common.OpenAPIV3Config
|
||||
spec *spec3.OpenAPI
|
||||
definitions map[string]common.OpenAPIDefinition
|
||||
}
|
||||
|
||||
func groupRoutesByPath(routes []common.Route) map[string][]common.Route {
|
||||
pathToRoutes := make(map[string][]common.Route)
|
||||
for _, r := range routes {
|
||||
pathToRoutes[r.Path()] = append(pathToRoutes[r.Path()], r)
|
||||
}
|
||||
return pathToRoutes
|
||||
}
|
||||
|
||||
func (o *openAPI) buildResponse(model interface{}, description string, content []string) (*spec3.Response, error) {
|
||||
response := &spec3.Response{
|
||||
ResponseProps: spec3.ResponseProps{
|
||||
Description: description,
|
||||
Content: make(map[string]*spec3.MediaType),
|
||||
},
|
||||
}
|
||||
|
||||
s, err := o.toSchema(util.GetCanonicalTypeName(model))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, contentType := range content {
|
||||
response.ResponseProps.Content[contentType] = &spec3.MediaType{
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: s,
|
||||
},
|
||||
}
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildOperations(route common.Route, inPathCommonParamsMap map[interface{}]*spec3.Parameter) (*spec3.Operation, error) {
|
||||
ret := &spec3.Operation{
|
||||
OperationProps: spec3.OperationProps{
|
||||
Description: route.Description(),
|
||||
Responses: &spec3.Responses{
|
||||
ResponsesProps: spec3.ResponsesProps{
|
||||
StatusCodeResponses: make(map[int]*spec3.Response),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for k, v := range route.Metadata() {
|
||||
if strings.HasPrefix(k, common.ExtensionPrefix) {
|
||||
if ret.Extensions == nil {
|
||||
ret.Extensions = spec.Extensions{}
|
||||
}
|
||||
ret.Extensions.Add(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
if ret.OperationId, ret.Tags, err = o.config.GetOperationIDAndTagsFromRoute(route); err != nil {
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Build responses
|
||||
for _, resp := range route.StatusCodeResponses() {
|
||||
ret.Responses.StatusCodeResponses[resp.Code()], err = o.buildResponse(resp.Model(), resp.Message(), route.Produces())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no response but a write sample, assume that write sample is an http.StatusOK response.
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 && route.ResponsePayloadSample() != nil {
|
||||
ret.Responses.StatusCodeResponses[http.StatusOK], err = o.buildResponse(route.ResponsePayloadSample(), "OK", route.Produces())
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
|
||||
for code, resp := range o.config.CommonResponses {
|
||||
if _, exists := ret.Responses.StatusCodeResponses[code]; !exists {
|
||||
ret.Responses.StatusCodeResponses[code] = resp
|
||||
}
|
||||
}
|
||||
|
||||
if len(ret.Responses.StatusCodeResponses) == 0 {
|
||||
ret.Responses.Default = o.config.DefaultResponse
|
||||
}
|
||||
|
||||
params := route.Parameters()
|
||||
for _, param := range params {
|
||||
_, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]
|
||||
if !isCommon && param.Kind() != common.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(param)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
ret.Parameters = append(ret.Parameters, openAPIParam)
|
||||
}
|
||||
}
|
||||
|
||||
body, err := o.buildRequestBody(params, route.Consumes(), route.RequestPayloadSample())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if body != nil {
|
||||
ret.RequestBody = body
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildRequestBody(parameters []common.Parameter, consumes []string, bodySample interface{}) (*spec3.RequestBody, error) {
|
||||
for _, param := range parameters {
|
||||
if param.Kind() == common.BodyParameterKind && bodySample != nil {
|
||||
schema, err := o.toSchema(util.GetCanonicalTypeName(bodySample))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &spec3.RequestBody{
|
||||
RequestBodyProps: spec3.RequestBodyProps{
|
||||
Content: map[string]*spec3.MediaType{},
|
||||
Description: param.Description(),
|
||||
Required: param.Required(),
|
||||
},
|
||||
}
|
||||
for _, consume := range consumes {
|
||||
r.Content[consume] = &spec3.MediaType{
|
||||
MediaTypeProps: spec3.MediaTypeProps{
|
||||
Schema: schema,
|
||||
},
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func newOpenAPI(config *common.OpenAPIV3Config) openAPI {
|
||||
o := openAPI{
|
||||
config: config,
|
||||
spec: &spec3.OpenAPI{
|
||||
Version: "3.0.0",
|
||||
Info: config.Info,
|
||||
Paths: &spec3.Paths{
|
||||
Paths: map[string]*spec3.Path{},
|
||||
},
|
||||
Components: &spec3.Components{
|
||||
Schemas: map[string]*spec.Schema{},
|
||||
},
|
||||
},
|
||||
}
|
||||
if len(o.config.ResponseDefinitions) > 0 {
|
||||
o.spec.Components.Responses = make(map[string]*spec3.Response)
|
||||
|
||||
}
|
||||
for k, response := range o.config.ResponseDefinitions {
|
||||
o.spec.Components.Responses[k] = response
|
||||
}
|
||||
|
||||
if len(o.config.SecuritySchemes) > 0 {
|
||||
o.spec.Components.SecuritySchemes = make(spec3.SecuritySchemes)
|
||||
|
||||
}
|
||||
for k, securityScheme := range o.config.SecuritySchemes {
|
||||
o.spec.Components.SecuritySchemes[k] = securityScheme
|
||||
}
|
||||
|
||||
if o.config.GetOperationIDAndTagsFromRoute == nil {
|
||||
// Map the deprecated handler to the common interface, if provided.
|
||||
if o.config.GetOperationIDAndTags != nil {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
restfulRouteAdapter, ok := r.(*restfuladapter.RouteAdapter)
|
||||
if !ok {
|
||||
return "", nil, fmt.Errorf("config.GetOperationIDAndTags specified but route is not a restful v1 Route")
|
||||
}
|
||||
|
||||
return o.config.GetOperationIDAndTags(restfulRouteAdapter.Route)
|
||||
}
|
||||
} else {
|
||||
o.config.GetOperationIDAndTagsFromRoute = func(r common.Route) (string, []string, error) {
|
||||
return r.OperationName(), nil, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if o.config.GetDefinitionName == nil {
|
||||
o.config.GetDefinitionName = func(name string) (string, spec.Extensions) {
|
||||
return name[strings.LastIndex(name, "/")+1:], nil
|
||||
}
|
||||
}
|
||||
|
||||
if o.config.Definitions != nil {
|
||||
o.definitions = o.config.Definitions
|
||||
} else {
|
||||
o.definitions = o.config.GetDefinitions(func(name string) spec.Ref {
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return spec.MustCreateRef("#/components/schemas/" + common.EscapeJsonPointer(defName))
|
||||
})
|
||||
}
|
||||
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *openAPI) buildOpenAPISpec(webServices []common.RouteContainer) error {
|
||||
pathsToIgnore := util.NewTrie(o.config.IgnorePrefixes)
|
||||
for _, w := range webServices {
|
||||
rootPath := w.RootPath()
|
||||
if pathsToIgnore.HasPrefix(rootPath) {
|
||||
continue
|
||||
}
|
||||
|
||||
commonParams, err := o.buildParameters(w.PathParameters())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for path, routes := range groupRoutesByPath(w.Routes()) {
|
||||
// go-swagger has special variable definition {$NAME:*} that can only be
|
||||
// used at the end of the path and it is not recognized by OpenAPI.
|
||||
if strings.HasSuffix(path, ":*}") {
|
||||
path = path[:len(path)-3] + "}"
|
||||
}
|
||||
if pathsToIgnore.HasPrefix(path) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Aggregating common parameters make API spec (and generated clients) simpler
|
||||
inPathCommonParamsMap, err := o.findCommonParameters(routes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pathItem, exists := o.spec.Paths.Paths[path]
|
||||
if exists {
|
||||
return fmt.Errorf("duplicate webservice route has been found for path: %v", path)
|
||||
}
|
||||
|
||||
pathItem = &spec3.Path{
|
||||
PathProps: spec3.PathProps{},
|
||||
}
|
||||
|
||||
// add web services's parameters as well as any parameters appears in all ops, as common parameters
|
||||
pathItem.Parameters = append(pathItem.Parameters, commonParams...)
|
||||
for _, p := range inPathCommonParamsMap {
|
||||
pathItem.Parameters = append(pathItem.Parameters, p)
|
||||
}
|
||||
sortParameters(pathItem.Parameters)
|
||||
|
||||
for _, route := range routes {
|
||||
op, err := o.buildOperations(route, inPathCommonParamsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sortParameters(op.Parameters)
|
||||
|
||||
switch strings.ToUpper(route.Method()) {
|
||||
case "GET":
|
||||
pathItem.Get = op
|
||||
case "POST":
|
||||
pathItem.Post = op
|
||||
case "HEAD":
|
||||
pathItem.Head = op
|
||||
case "PUT":
|
||||
pathItem.Put = op
|
||||
case "DELETE":
|
||||
pathItem.Delete = op
|
||||
case "OPTIONS":
|
||||
pathItem.Options = op
|
||||
case "PATCH":
|
||||
pathItem.Patch = op
|
||||
}
|
||||
|
||||
}
|
||||
o.spec.Paths.Paths[path] = pathItem
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildOpenAPISpec builds OpenAPI v3 spec given a list of route containers and common.Config to customize it.
|
||||
//
|
||||
// Deprecated: BuildOpenAPISpecFromRoutes should be used instead.
|
||||
func BuildOpenAPISpec(webServices []*restful.WebService, config *common.OpenAPIV3Config) (*spec3.OpenAPI, error) {
|
||||
return BuildOpenAPISpecFromRoutes(restfuladapter.AdaptWebServices(webServices), config)
|
||||
}
|
||||
|
||||
// BuildOpenAPISpecFromRoutes builds OpenAPI v3 spec given a list of route containers and common.Config to customize it.
|
||||
func BuildOpenAPISpecFromRoutes(webServices []common.RouteContainer, config *common.OpenAPIV3Config) (*spec3.OpenAPI, error) {
|
||||
a := newOpenAPI(config)
|
||||
err := a.buildOpenAPISpec(webServices)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if config.PostProcessSpec != nil {
|
||||
return config.PostProcessSpec(a.spec)
|
||||
}
|
||||
return a.spec, nil
|
||||
}
|
||||
|
||||
// BuildOpenAPIDefinitionsForResource builds a partial OpenAPI spec given a sample object and common.Config to customize it.
|
||||
// BuildOpenAPIDefinitionsForResources returns the OpenAPI spec which includes the definitions for the
|
||||
// passed type names.
|
||||
func BuildOpenAPIDefinitionsForResources(config *common.OpenAPIV3Config, names ...string) (map[string]*spec.Schema, error) {
|
||||
o := newOpenAPI(config)
|
||||
// We can discard the return value of toSchema because all we care about is the side effect of calling it.
|
||||
// All the models created for this resource get added to o.swagger.Definitions
|
||||
for _, name := range names {
|
||||
_, err := o.toSchema(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return o.spec.Components.Schemas, nil
|
||||
}
|
||||
func (o *openAPI) findCommonParameters(routes []common.Route) (map[interface{}]*spec3.Parameter, error) {
|
||||
commonParamsMap := make(map[interface{}]*spec3.Parameter, 0)
|
||||
paramOpsCountByName := make(map[interface{}]int, 0)
|
||||
paramNameKindToDataMap := make(map[interface{}]common.Parameter, 0)
|
||||
for _, route := range routes {
|
||||
routeParamDuplicateMap := make(map[interface{}]bool)
|
||||
s := ""
|
||||
params := route.Parameters()
|
||||
for _, param := range params {
|
||||
m, _ := json.Marshal(param)
|
||||
s += string(m) + "\n"
|
||||
key := mapKeyFromParam(param)
|
||||
if routeParamDuplicateMap[key] {
|
||||
msg, _ := json.Marshal(params)
|
||||
return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v", param.Name(), string(msg), s)
|
||||
}
|
||||
routeParamDuplicateMap[key] = true
|
||||
paramOpsCountByName[key]++
|
||||
paramNameKindToDataMap[key] = param
|
||||
}
|
||||
}
|
||||
for key, count := range paramOpsCountByName {
|
||||
paramData := paramNameKindToDataMap[key]
|
||||
if count == len(routes) && paramData.Kind() != common.BodyParameterKind {
|
||||
openAPIParam, err := o.buildParameter(paramData)
|
||||
if err != nil {
|
||||
return commonParamsMap, err
|
||||
}
|
||||
commonParamsMap[key] = openAPIParam
|
||||
}
|
||||
}
|
||||
return commonParamsMap, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameters(restParam []common.Parameter) (ret []*spec3.Parameter, err error) {
|
||||
ret = make([]*spec3.Parameter, len(restParam))
|
||||
for i, v := range restParam {
|
||||
ret[i], err = o.buildParameter(v)
|
||||
if err != nil {
|
||||
return ret, err
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildParameter(restParam common.Parameter) (ret *spec3.Parameter, err error) {
|
||||
ret = &spec3.Parameter{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: restParam.Name(),
|
||||
Description: restParam.Description(),
|
||||
Required: restParam.Required(),
|
||||
},
|
||||
}
|
||||
switch restParam.Kind() {
|
||||
case common.BodyParameterKind:
|
||||
return nil, nil
|
||||
case common.PathParameterKind:
|
||||
ret.In = "path"
|
||||
if !restParam.Required() {
|
||||
return ret, fmt.Errorf("path parameters should be marked as required for parameter %v", restParam)
|
||||
}
|
||||
case common.QueryParameterKind:
|
||||
ret.In = "query"
|
||||
case common.HeaderParameterKind:
|
||||
ret.In = "header"
|
||||
/* TODO: add support for the cookie param */
|
||||
default:
|
||||
return ret, fmt.Errorf("unsupported restful parameter kind : %v", restParam.Kind())
|
||||
}
|
||||
openAPIType, openAPIFormat := common.OpenAPITypeFormat(restParam.DataType())
|
||||
if openAPIType == "" {
|
||||
return ret, fmt.Errorf("non-body Restful parameter type should be a simple type, but got : %v", restParam.DataType())
|
||||
}
|
||||
|
||||
ret.Schema = &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
UniqueItems: !restParam.AllowMultiple(),
|
||||
},
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionRecursively(name string) error {
|
||||
uniqueName, extensions := o.config.GetDefinitionName(name)
|
||||
if _, ok := o.spec.Components.Schemas[uniqueName]; ok {
|
||||
return nil
|
||||
}
|
||||
if item, ok := o.definitions[name]; ok {
|
||||
schema := &spec.Schema{
|
||||
VendorExtensible: item.Schema.VendorExtensible,
|
||||
SchemaProps: item.Schema.SchemaProps,
|
||||
SwaggerSchemaProps: item.Schema.SwaggerSchemaProps,
|
||||
}
|
||||
if extensions != nil {
|
||||
if schema.Extensions == nil {
|
||||
schema.Extensions = spec.Extensions{}
|
||||
}
|
||||
for k, v := range extensions {
|
||||
schema.Extensions[k] = v
|
||||
}
|
||||
}
|
||||
// delete the embedded v2 schema if exists, otherwise no-op
|
||||
delete(schema.VendorExtensible.Extensions, common.ExtensionV2Schema)
|
||||
schema = builderutil.WrapRefs(schema)
|
||||
o.spec.Components.Schemas[uniqueName] = schema
|
||||
for _, v := range item.Dependencies {
|
||||
if err := o.buildDefinitionRecursively(v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("cannot find model definition for %v. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *openAPI) buildDefinitionForType(name string) (string, error) {
|
||||
if err := o.buildDefinitionRecursively(name); err != nil {
|
||||
return "", err
|
||||
}
|
||||
defName, _ := o.config.GetDefinitionName(name)
|
||||
return "#/components/schemas/" + common.EscapeJsonPointer(defName), nil
|
||||
}
|
||||
|
||||
func (o *openAPI) toSchema(name string) (_ *spec.Schema, err error) {
|
||||
if openAPIType, openAPIFormat := common.OpenAPITypeFormat(name); openAPIType != "" {
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Type: []string{openAPIType},
|
||||
Format: openAPIFormat,
|
||||
},
|
||||
}, nil
|
||||
} else {
|
||||
ref, err := o.buildDefinitionForType(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &spec.Schema{
|
||||
SchemaProps: spec.SchemaProps{
|
||||
Ref: spec.MustCreateRef(ref),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
52
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util.go
generated
vendored
52
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util.go
generated
vendored
@ -1,52 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 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 builder3
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
)
|
||||
|
||||
func mapKeyFromParam(param common.Parameter) interface{} {
|
||||
return struct {
|
||||
Name string
|
||||
Kind common.ParameterKind
|
||||
}{
|
||||
Name: param.Name(),
|
||||
Kind: param.Kind(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s parameters) Len() int { return len(s) }
|
||||
func (s parameters) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||
|
||||
type parameters []*spec3.Parameter
|
||||
|
||||
type byNameIn struct {
|
||||
parameters
|
||||
}
|
||||
|
||||
func (s byNameIn) Less(i, j int) bool {
|
||||
return s.parameters[i].Name < s.parameters[j].Name || (s.parameters[i].Name == s.parameters[j].Name && s.parameters[i].In < s.parameters[j].In)
|
||||
}
|
||||
|
||||
// SortParameters sorts parameters by Name and In fields.
|
||||
func sortParameters(p []*spec3.Parameter) {
|
||||
sort.Sort(byNameIn{p})
|
||||
}
|
51
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go
generated
vendored
51
e2e/vendor/k8s.io/kube-openapi/pkg/builder3/util/util.go
generated
vendored
@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 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 util
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"k8s.io/kube-openapi/pkg/schemamutation"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// wrapRefs wraps OpenAPI V3 Schema refs that contain sibling elements.
|
||||
// AllOf is used to wrap the Ref to prevent references from having sibling elements
|
||||
// Please see https://github.com/kubernetes/kubernetes/issues/106387#issuecomment-967640388
|
||||
func WrapRefs(schema *spec.Schema) *spec.Schema {
|
||||
walker := schemamutation.Walker{
|
||||
SchemaCallback: func(schema *spec.Schema) *spec.Schema {
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = new(spec.Schema)
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
if schema.Ref.String() != "" && !reflect.DeepEqual(*schema, spec.Schema{SchemaProps: spec.SchemaProps{Ref: schema.Ref}}) {
|
||||
clone()
|
||||
refSchema := new(spec.Schema)
|
||||
refSchema.Ref = schema.Ref
|
||||
schema.Ref = spec.Ref{}
|
||||
schema.AllOf = []spec.Schema{*refSchema}
|
||||
}
|
||||
return schema
|
||||
},
|
||||
RefCallback: schemamutation.RefCallbackNoop,
|
||||
}
|
||||
return walker.WalkSchema(schema)
|
||||
}
|
15
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/adapter.go
generated
vendored
15
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/adapter.go
generated
vendored
@ -1,15 +0,0 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
// AdaptWebServices adapts a slice of restful.WebService into the common interfaces.
|
||||
func AdaptWebServices(webServices []*restful.WebService) []common.RouteContainer {
|
||||
var containers []common.RouteContainer
|
||||
for _, ws := range webServices {
|
||||
containers = append(containers, &WebServiceAdapter{ws})
|
||||
}
|
||||
return containers
|
||||
}
|
54
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/param_adapter.go
generated
vendored
54
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/param_adapter.go
generated
vendored
@ -1,54 +0,0 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.Parameter = &ParamAdapter{}
|
||||
|
||||
type ParamAdapter struct {
|
||||
Param *restful.Parameter
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(r.Param)
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Name() string {
|
||||
return r.Param.Data().Name
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Description() string {
|
||||
return r.Param.Data().Description
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Required() bool {
|
||||
return r.Param.Data().Required
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) Kind() common.ParameterKind {
|
||||
switch r.Param.Kind() {
|
||||
case restful.PathParameterKind:
|
||||
return common.PathParameterKind
|
||||
case restful.QueryParameterKind:
|
||||
return common.QueryParameterKind
|
||||
case restful.BodyParameterKind:
|
||||
return common.BodyParameterKind
|
||||
case restful.HeaderParameterKind:
|
||||
return common.HeaderParameterKind
|
||||
case restful.FormParameterKind:
|
||||
return common.FormParameterKind
|
||||
default:
|
||||
return common.UnknownParameterKind
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) DataType() string {
|
||||
return r.Param.Data().DataType
|
||||
}
|
||||
|
||||
func (r *ParamAdapter) AllowMultiple() bool {
|
||||
return r.Param.Data().AllowMultiple
|
||||
}
|
25
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/response_error_adapter.go
generated
vendored
25
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/response_error_adapter.go
generated
vendored
@ -1,25 +0,0 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.StatusCodeResponse = &ResponseErrorAdapter{}
|
||||
|
||||
// ResponseErrorAdapter adapts a restful.ResponseError to common.StatusCodeResponse.
|
||||
type ResponseErrorAdapter struct {
|
||||
Err *restful.ResponseError
|
||||
}
|
||||
|
||||
func (r *ResponseErrorAdapter) Message() string {
|
||||
return r.Err.Message
|
||||
}
|
||||
|
||||
func (r *ResponseErrorAdapter) Model() interface{} {
|
||||
return r.Err.Model
|
||||
}
|
||||
|
||||
func (r *ResponseErrorAdapter) Code() int {
|
||||
return r.Err.Code
|
||||
}
|
68
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/route_adapter.go
generated
vendored
68
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/route_adapter.go
generated
vendored
@ -1,68 +0,0 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.Route = &RouteAdapter{}
|
||||
|
||||
// RouteAdapter adapts a restful.Route to common.Route.
|
||||
type RouteAdapter struct {
|
||||
Route *restful.Route
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) StatusCodeResponses() []common.StatusCodeResponse {
|
||||
// go-restful uses the ResponseErrors field to contain both error and regular responses.
|
||||
var responses []common.StatusCodeResponse
|
||||
for _, res := range r.Route.ResponseErrors {
|
||||
localRes := res
|
||||
responses = append(responses, &ResponseErrorAdapter{&localRes})
|
||||
}
|
||||
|
||||
return responses
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) OperationName() string {
|
||||
return r.Route.Operation
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Method() string {
|
||||
return r.Route.Method
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Path() string {
|
||||
return r.Route.Path
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Parameters() []common.Parameter {
|
||||
var params []common.Parameter
|
||||
for _, rParam := range r.Route.ParameterDocs {
|
||||
params = append(params, &ParamAdapter{rParam})
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Description() string {
|
||||
return r.Route.Doc
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Consumes() []string {
|
||||
return r.Route.Consumes
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Produces() []string {
|
||||
return r.Route.Produces
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) Metadata() map[string]interface{} {
|
||||
return r.Route.Metadata
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) RequestPayloadSample() interface{} {
|
||||
return r.Route.ReadSample
|
||||
}
|
||||
|
||||
func (r *RouteAdapter) ResponsePayloadSample() interface{} {
|
||||
return r.Route.WriteSample
|
||||
}
|
34
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/webservice_adapter.go
generated
vendored
34
e2e/vendor/k8s.io/kube-openapi/pkg/common/restfuladapter/webservice_adapter.go
generated
vendored
@ -1,34 +0,0 @@
|
||||
package restfuladapter
|
||||
|
||||
import (
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
)
|
||||
|
||||
var _ common.RouteContainer = &WebServiceAdapter{}
|
||||
|
||||
// WebServiceAdapter adapts a restful.WebService to common.RouteContainer.
|
||||
type WebServiceAdapter struct {
|
||||
WebService *restful.WebService
|
||||
}
|
||||
|
||||
func (r *WebServiceAdapter) RootPath() string {
|
||||
return r.WebService.RootPath()
|
||||
}
|
||||
|
||||
func (r *WebServiceAdapter) PathParameters() []common.Parameter {
|
||||
var params []common.Parameter
|
||||
for _, rParam := range r.WebService.PathParameters() {
|
||||
params = append(params, &ParamAdapter{rParam})
|
||||
}
|
||||
return params
|
||||
}
|
||||
|
||||
func (r *WebServiceAdapter) Routes() []common.Route {
|
||||
var routes []common.Route
|
||||
for _, rRoute := range r.WebService.Routes() {
|
||||
localRoute := rRoute
|
||||
routes = append(routes, &RouteAdapter{&localRoute})
|
||||
}
|
||||
return routes
|
||||
}
|
208
e2e/vendor/k8s.io/kube-openapi/pkg/handler/default_pruning.go
generated
vendored
208
e2e/vendor/k8s.io/kube-openapi/pkg/handler/default_pruning.go
generated
vendored
@ -1,208 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 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 handler
|
||||
|
||||
import "k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
// PruneDefaults remove all the defaults recursively from all the
|
||||
// schemas in the definitions, and does not modify the definitions in
|
||||
// place.
|
||||
func PruneDefaults(definitions spec.Definitions) spec.Definitions {
|
||||
definitionsCloned := false
|
||||
for k, v := range definitions {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
orig := definitions
|
||||
definitions = make(spec.Definitions, len(orig))
|
||||
for k2, v2 := range orig {
|
||||
definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
definitions[k] = *s
|
||||
}
|
||||
}
|
||||
return definitions
|
||||
}
|
||||
|
||||
// PruneDefaultsSchema remove all the defaults recursively from the
|
||||
// schema in place.
|
||||
func PruneDefaultsSchema(schema *spec.Schema) *spec.Schema {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = &spec.Schema{}
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Default != nil {
|
||||
clone()
|
||||
schema.Default = nil
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range schema.Definitions {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
schema.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
schema.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
propertiesCloned := false
|
||||
for k, v := range schema.Properties {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !propertiesCloned {
|
||||
propertiesCloned = true
|
||||
clone()
|
||||
schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
|
||||
for k2, v2 := range orig.Properties {
|
||||
schema.Properties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Properties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
patternPropertiesCloned := false
|
||||
for k, v := range schema.PatternProperties {
|
||||
if s := PruneDefaultsSchema(&v); s != &v {
|
||||
if !patternPropertiesCloned {
|
||||
patternPropertiesCloned = true
|
||||
clone()
|
||||
schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
|
||||
for k2, v2 := range orig.PatternProperties {
|
||||
schema.PatternProperties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.PatternProperties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
dependenciesCloned := false
|
||||
for k, v := range schema.Dependencies {
|
||||
if s := PruneDefaultsSchema(v.Schema); s != v.Schema {
|
||||
if !dependenciesCloned {
|
||||
dependenciesCloned = true
|
||||
clone()
|
||||
schema.Dependencies = make(spec.Dependencies, len(orig.Dependencies))
|
||||
for k2, v2 := range orig.Dependencies {
|
||||
schema.Dependencies[k2] = v2
|
||||
}
|
||||
}
|
||||
v.Schema = s
|
||||
schema.Dependencies[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
allOfCloned := false
|
||||
for i := range schema.AllOf {
|
||||
if s := PruneDefaultsSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
|
||||
if !allOfCloned {
|
||||
allOfCloned = true
|
||||
clone()
|
||||
schema.AllOf = make([]spec.Schema, len(orig.AllOf))
|
||||
copy(schema.AllOf, orig.AllOf)
|
||||
}
|
||||
schema.AllOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
anyOfCloned := false
|
||||
for i := range schema.AnyOf {
|
||||
if s := PruneDefaultsSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
|
||||
if !anyOfCloned {
|
||||
anyOfCloned = true
|
||||
clone()
|
||||
schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
|
||||
copy(schema.AnyOf, orig.AnyOf)
|
||||
}
|
||||
schema.AnyOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
oneOfCloned := false
|
||||
for i := range schema.OneOf {
|
||||
if s := PruneDefaultsSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
|
||||
if !oneOfCloned {
|
||||
oneOfCloned = true
|
||||
clone()
|
||||
schema.OneOf = make([]spec.Schema, len(orig.OneOf))
|
||||
copy(schema.OneOf, orig.OneOf)
|
||||
}
|
||||
schema.OneOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Not != nil {
|
||||
if s := PruneDefaultsSchema(schema.Not); s != schema.Not {
|
||||
clone()
|
||||
schema.Not = s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
if s := PruneDefaultsSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
|
||||
clone()
|
||||
schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
if s := PruneDefaultsSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
|
||||
clone()
|
||||
schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
if s := PruneDefaultsSchema(schema.Items.Schema); s != schema.Items.Schema {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{Schema: s}
|
||||
}
|
||||
} else {
|
||||
itemsCloned := false
|
||||
for i := range schema.Items.Schemas {
|
||||
if s := PruneDefaultsSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
|
||||
if !itemsCloned {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{
|
||||
Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
|
||||
}
|
||||
itemsCloned = true
|
||||
copy(schema.Items.Schemas, orig.Items.Schemas)
|
||||
}
|
||||
schema.Items.Schemas[i] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
202
e2e/vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
202
e2e/vendor/k8s.io/kube-openapi/pkg/handler/handler.go
generated
vendored
@ -1,202 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 handler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/NYTimes/gziphandler"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
openapi_v2 "github.com/google/gnostic-models/openapiv2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/munnerz/goautoneg"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
klog "k8s.io/klog/v2"
|
||||
"k8s.io/kube-openapi/pkg/builder"
|
||||
"k8s.io/kube-openapi/pkg/cached"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/common/restfuladapter"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
const (
|
||||
subTypeProtobufDeprecated = "com.github.proto-openapi.spec.v2@v1.0+protobuf"
|
||||
subTypeProtobuf = "com.github.proto-openapi.spec.v2.v1.0+protobuf"
|
||||
subTypeJSON = "json"
|
||||
)
|
||||
|
||||
func computeETag(data []byte) string {
|
||||
if data == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%X", sha512.Sum512(data))
|
||||
}
|
||||
|
||||
type timedSpec struct {
|
||||
spec []byte
|
||||
lastModified time.Time
|
||||
}
|
||||
|
||||
// OpenAPIService is the service responsible for serving OpenAPI spec. It has
|
||||
// the ability to safely change the spec while serving it.
|
||||
type OpenAPIService struct {
|
||||
specCache cached.LastSuccess[*spec.Swagger]
|
||||
jsonCache cached.Value[timedSpec]
|
||||
protoCache cached.Value[timedSpec]
|
||||
}
|
||||
|
||||
// NewOpenAPIService builds an OpenAPIService starting with the given spec.
|
||||
func NewOpenAPIService(swagger *spec.Swagger) *OpenAPIService {
|
||||
return NewOpenAPIServiceLazy(cached.Static(swagger, uuid.New().String()))
|
||||
}
|
||||
|
||||
// NewOpenAPIServiceLazy builds an OpenAPIService from lazy spec.
|
||||
func NewOpenAPIServiceLazy(swagger cached.Value[*spec.Swagger]) *OpenAPIService {
|
||||
o := &OpenAPIService{}
|
||||
o.UpdateSpecLazy(swagger)
|
||||
|
||||
o.jsonCache = cached.Transform[*spec.Swagger](func(spec *spec.Swagger, etag string, err error) (timedSpec, string, error) {
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
json, err := spec.MarshalJSON()
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
return timedSpec{spec: json, lastModified: time.Now()}, computeETag(json), nil
|
||||
}, &o.specCache)
|
||||
o.protoCache = cached.Transform(func(ts timedSpec, etag string, err error) (timedSpec, string, error) {
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
proto, err := ToProtoBinary(ts.spec)
|
||||
if err != nil {
|
||||
return timedSpec{}, "", err
|
||||
}
|
||||
// We can re-use the same etag as json because of the Vary header.
|
||||
return timedSpec{spec: proto, lastModified: ts.lastModified}, etag, nil
|
||||
}, o.jsonCache)
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateSpec(swagger *spec.Swagger) error {
|
||||
o.UpdateSpecLazy(cached.Static(swagger, uuid.New().String()))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *OpenAPIService) UpdateSpecLazy(swagger cached.Value[*spec.Swagger]) {
|
||||
o.specCache.Store(swagger)
|
||||
}
|
||||
|
||||
func ToProtoBinary(json []byte) ([]byte, error) {
|
||||
document, err := openapi_v2.ParseDocument(json)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return proto.Marshal(document)
|
||||
}
|
||||
|
||||
// RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec.
|
||||
//
|
||||
// Deprecated: use OpenAPIService.RegisterOpenAPIVersionedService instead.
|
||||
func RegisterOpenAPIVersionedService(spec *spec.Swagger, servePath string, handler common.PathHandler) *OpenAPIService {
|
||||
o := NewOpenAPIService(spec)
|
||||
o.RegisterOpenAPIVersionedService(servePath, handler)
|
||||
return o
|
||||
}
|
||||
|
||||
// RegisterOpenAPIVersionedService registers a handler to provide access to provided swagger spec.
|
||||
func (o *OpenAPIService) RegisterOpenAPIVersionedService(servePath string, handler common.PathHandler) {
|
||||
accepted := []struct {
|
||||
Type string
|
||||
SubType string
|
||||
ReturnedContentType string
|
||||
GetDataAndEtag cached.Value[timedSpec]
|
||||
}{
|
||||
{"application", subTypeJSON, "application/" + subTypeJSON, o.jsonCache},
|
||||
{"application", subTypeProtobufDeprecated, "application/" + subTypeProtobuf, o.protoCache},
|
||||
{"application", subTypeProtobuf, "application/" + subTypeProtobuf, o.protoCache},
|
||||
}
|
||||
|
||||
handler.Handle(servePath, gziphandler.GzipHandler(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
decipherableFormats := r.Header.Get("Accept")
|
||||
if decipherableFormats == "" {
|
||||
decipherableFormats = "*/*"
|
||||
}
|
||||
clauses := goautoneg.ParseAccept(decipherableFormats)
|
||||
w.Header().Add("Vary", "Accept")
|
||||
for _, clause := range clauses {
|
||||
for _, accepts := range accepted {
|
||||
if clause.Type != accepts.Type && clause.Type != "*" {
|
||||
continue
|
||||
}
|
||||
if clause.SubType != accepts.SubType && clause.SubType != "*" {
|
||||
continue
|
||||
}
|
||||
// serve the first matching media type in the sorted clause list
|
||||
ts, etag, err := accepts.GetDataAndEtag.Get()
|
||||
if err != nil {
|
||||
klog.Errorf("Error in OpenAPI handler: %s", err)
|
||||
// only return a 503 if we have no older cache data to serve
|
||||
if ts.spec == nil {
|
||||
w.WriteHeader(http.StatusServiceUnavailable)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Set Content-Type header in the reponse
|
||||
w.Header().Set("Content-Type", accepts.ReturnedContentType)
|
||||
|
||||
// ETag must be enclosed in double quotes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
||||
w.Header().Set("Etag", strconv.Quote(etag))
|
||||
// ServeContent will take care of caching using eTag.
|
||||
http.ServeContent(w, r, servePath, ts.lastModified, bytes.NewReader(ts.spec))
|
||||
return
|
||||
}
|
||||
}
|
||||
// Return 406 for not acceptable format
|
||||
w.WriteHeader(406)
|
||||
return
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
// BuildAndRegisterOpenAPIVersionedService builds the spec and registers a handler to provide access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIVersionedService.
|
||||
//
|
||||
// Deprecated: BuildAndRegisterOpenAPIVersionedServiceFromRoutes should be used instead.
|
||||
func BuildAndRegisterOpenAPIVersionedService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
return BuildAndRegisterOpenAPIVersionedServiceFromRoutes(servePath, restfuladapter.AdaptWebServices(webServices), config, handler)
|
||||
}
|
||||
|
||||
// BuildAndRegisterOpenAPIVersionedServiceFromRoutes builds the spec and registers a handler to provide access to it.
|
||||
// Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIVersionedService.
|
||||
func BuildAndRegisterOpenAPIVersionedServiceFromRoutes(servePath string, routeContainers []common.RouteContainer, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) {
|
||||
spec, err := builder.BuildOpenAPISpecFromRoutes(routeContainers, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
o := NewOpenAPIService(spec)
|
||||
o.RegisterOpenAPIVersionedService(servePath, handler)
|
||||
return o, nil
|
||||
}
|
519
e2e/vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go
generated
vendored
519
e2e/vendor/k8s.io/kube-openapi/pkg/schemamutation/walker.go
generated
vendored
@ -1,519 +0,0 @@
|
||||
/*
|
||||
Copyright 2017 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 schemamutation
|
||||
|
||||
import (
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
)
|
||||
|
||||
// Walker runs callback functions on all references of an OpenAPI spec,
|
||||
// replacing the values when visiting corresponding types.
|
||||
type Walker struct {
|
||||
// SchemaCallback will be called on each schema, taking the original schema,
|
||||
// and before any other callbacks of the Walker.
|
||||
// If the schema needs to be mutated, DO NOT mutate it in-place,
|
||||
// always create a copy, mutate, and return it.
|
||||
SchemaCallback func(schema *spec.Schema) *spec.Schema
|
||||
|
||||
// RefCallback will be called on each ref.
|
||||
// If the ref needs to be mutated, DO NOT mutate it in-place,
|
||||
// always create a copy, mutate, and return it.
|
||||
RefCallback func(ref *spec.Ref) *spec.Ref
|
||||
}
|
||||
|
||||
type SchemaCallbackFunc func(schema *spec.Schema) *spec.Schema
|
||||
type RefCallbackFunc func(ref *spec.Ref) *spec.Ref
|
||||
|
||||
var SchemaCallBackNoop SchemaCallbackFunc = func(schema *spec.Schema) *spec.Schema {
|
||||
return schema
|
||||
}
|
||||
var RefCallbackNoop RefCallbackFunc = func(ref *spec.Ref) *spec.Ref {
|
||||
return ref
|
||||
}
|
||||
|
||||
// ReplaceReferences rewrites the references without mutating the input.
|
||||
// The output might share data with the input.
|
||||
func ReplaceReferences(walkRef func(ref *spec.Ref) *spec.Ref, sp *spec.Swagger) *spec.Swagger {
|
||||
walker := &Walker{RefCallback: walkRef, SchemaCallback: SchemaCallBackNoop}
|
||||
return walker.WalkRoot(sp)
|
||||
}
|
||||
|
||||
func (w *Walker) WalkSchema(schema *spec.Schema) *spec.Schema {
|
||||
if schema == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := schema
|
||||
clone := func() {
|
||||
if orig == schema {
|
||||
schema = &spec.Schema{}
|
||||
*schema = *orig
|
||||
}
|
||||
}
|
||||
|
||||
// Always run callback on the whole schema first
|
||||
// so that SchemaCallback can take the original schema as input.
|
||||
schema = w.SchemaCallback(schema)
|
||||
|
||||
if r := w.RefCallback(&schema.Ref); r != &schema.Ref {
|
||||
clone()
|
||||
schema.Ref = *r
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range schema.Definitions {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
schema.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
schema.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
propertiesCloned := false
|
||||
for k, v := range schema.Properties {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !propertiesCloned {
|
||||
propertiesCloned = true
|
||||
clone()
|
||||
schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
|
||||
for k2, v2 := range orig.Properties {
|
||||
schema.Properties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.Properties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
patternPropertiesCloned := false
|
||||
for k, v := range schema.PatternProperties {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !patternPropertiesCloned {
|
||||
patternPropertiesCloned = true
|
||||
clone()
|
||||
schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
|
||||
for k2, v2 := range orig.PatternProperties {
|
||||
schema.PatternProperties[k2] = v2
|
||||
}
|
||||
}
|
||||
schema.PatternProperties[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
allOfCloned := false
|
||||
for i := range schema.AllOf {
|
||||
if s := w.WalkSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
|
||||
if !allOfCloned {
|
||||
allOfCloned = true
|
||||
clone()
|
||||
schema.AllOf = make([]spec.Schema, len(orig.AllOf))
|
||||
copy(schema.AllOf, orig.AllOf)
|
||||
}
|
||||
schema.AllOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
anyOfCloned := false
|
||||
for i := range schema.AnyOf {
|
||||
if s := w.WalkSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
|
||||
if !anyOfCloned {
|
||||
anyOfCloned = true
|
||||
clone()
|
||||
schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
|
||||
copy(schema.AnyOf, orig.AnyOf)
|
||||
}
|
||||
schema.AnyOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
oneOfCloned := false
|
||||
for i := range schema.OneOf {
|
||||
if s := w.WalkSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
|
||||
if !oneOfCloned {
|
||||
oneOfCloned = true
|
||||
clone()
|
||||
schema.OneOf = make([]spec.Schema, len(orig.OneOf))
|
||||
copy(schema.OneOf, orig.OneOf)
|
||||
}
|
||||
schema.OneOf[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Not != nil {
|
||||
if s := w.WalkSchema(schema.Not); s != schema.Not {
|
||||
clone()
|
||||
schema.Not = s
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
|
||||
if s := w.WalkSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
|
||||
clone()
|
||||
schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
|
||||
if s := w.WalkSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
|
||||
clone()
|
||||
schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
|
||||
}
|
||||
}
|
||||
|
||||
if schema.Items != nil {
|
||||
if schema.Items.Schema != nil {
|
||||
if s := w.WalkSchema(schema.Items.Schema); s != schema.Items.Schema {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{Schema: s}
|
||||
}
|
||||
} else {
|
||||
itemsCloned := false
|
||||
for i := range schema.Items.Schemas {
|
||||
if s := w.WalkSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
|
||||
if !itemsCloned {
|
||||
clone()
|
||||
schema.Items = &spec.SchemaOrArray{
|
||||
Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
|
||||
}
|
||||
itemsCloned = true
|
||||
copy(schema.Items.Schemas, orig.Items.Schemas)
|
||||
}
|
||||
schema.Items.Schemas[i] = *s
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
func (w *Walker) walkParameter(param *spec.Parameter) *spec.Parameter {
|
||||
if param == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := param
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
param = &spec.Parameter{}
|
||||
*param = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.RefCallback(¶m.Ref); r != ¶m.Ref {
|
||||
clone()
|
||||
param.Ref = *r
|
||||
}
|
||||
if s := w.WalkSchema(param.Schema); s != param.Schema {
|
||||
clone()
|
||||
param.Schema = s
|
||||
}
|
||||
if param.Items != nil {
|
||||
if r := w.RefCallback(¶m.Items.Ref); r != ¶m.Items.Ref {
|
||||
param.Items.Ref = *r
|
||||
}
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
||||
|
||||
func (w *Walker) walkParameters(params []spec.Parameter) ([]spec.Parameter, bool) {
|
||||
if params == nil {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
orig := params
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
params = make([]spec.Parameter, len(params))
|
||||
copy(params, orig)
|
||||
}
|
||||
}
|
||||
|
||||
for i := range params {
|
||||
if s := w.walkParameter(¶ms[i]); s != ¶ms[i] {
|
||||
clone()
|
||||
params[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
return params, cloned
|
||||
}
|
||||
|
||||
func (w *Walker) walkResponse(resp *spec.Response) *spec.Response {
|
||||
if resp == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := resp
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
resp = &spec.Response{}
|
||||
*resp = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.RefCallback(&resp.Ref); r != &resp.Ref {
|
||||
clone()
|
||||
resp.Ref = *r
|
||||
}
|
||||
if s := w.WalkSchema(resp.Schema); s != resp.Schema {
|
||||
clone()
|
||||
resp.Schema = s
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func (w *Walker) walkResponses(resps *spec.Responses) *spec.Responses {
|
||||
if resps == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := resps
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
resps = &spec.Responses{}
|
||||
*resps = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.walkResponse(resps.ResponsesProps.Default); r != resps.ResponsesProps.Default {
|
||||
clone()
|
||||
resps.Default = r
|
||||
}
|
||||
|
||||
responsesCloned := false
|
||||
for k, v := range resps.ResponsesProps.StatusCodeResponses {
|
||||
if r := w.walkResponse(&v); r != &v {
|
||||
if !responsesCloned {
|
||||
responsesCloned = true
|
||||
clone()
|
||||
resps.ResponsesProps.StatusCodeResponses = make(map[int]spec.Response, len(orig.StatusCodeResponses))
|
||||
for k2, v2 := range orig.StatusCodeResponses {
|
||||
resps.ResponsesProps.StatusCodeResponses[k2] = v2
|
||||
}
|
||||
}
|
||||
resps.ResponsesProps.StatusCodeResponses[k] = *r
|
||||
}
|
||||
}
|
||||
|
||||
return resps
|
||||
}
|
||||
|
||||
func (w *Walker) walkOperation(op *spec.Operation) *spec.Operation {
|
||||
if op == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := op
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
op = &spec.Operation{}
|
||||
*op = *orig
|
||||
}
|
||||
}
|
||||
|
||||
parametersCloned := false
|
||||
for i := range op.Parameters {
|
||||
if s := w.walkParameter(&op.Parameters[i]); s != &op.Parameters[i] {
|
||||
if !parametersCloned {
|
||||
parametersCloned = true
|
||||
clone()
|
||||
op.Parameters = make([]spec.Parameter, len(orig.Parameters))
|
||||
copy(op.Parameters, orig.Parameters)
|
||||
}
|
||||
op.Parameters[i] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if r := w.walkResponses(op.Responses); r != op.Responses {
|
||||
clone()
|
||||
op.Responses = r
|
||||
}
|
||||
|
||||
return op
|
||||
}
|
||||
|
||||
func (w *Walker) walkPathItem(pathItem *spec.PathItem) *spec.PathItem {
|
||||
if pathItem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := pathItem
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
pathItem = &spec.PathItem{}
|
||||
*pathItem = *orig
|
||||
}
|
||||
}
|
||||
|
||||
if p, changed := w.walkParameters(pathItem.Parameters); changed {
|
||||
clone()
|
||||
pathItem.Parameters = p
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Get); op != pathItem.Get {
|
||||
clone()
|
||||
pathItem.Get = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Head); op != pathItem.Head {
|
||||
clone()
|
||||
pathItem.Head = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Delete); op != pathItem.Delete {
|
||||
clone()
|
||||
pathItem.Delete = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Options); op != pathItem.Options {
|
||||
clone()
|
||||
pathItem.Options = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Patch); op != pathItem.Patch {
|
||||
clone()
|
||||
pathItem.Patch = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Post); op != pathItem.Post {
|
||||
clone()
|
||||
pathItem.Post = op
|
||||
}
|
||||
if op := w.walkOperation(pathItem.Put); op != pathItem.Put {
|
||||
clone()
|
||||
pathItem.Put = op
|
||||
}
|
||||
|
||||
return pathItem
|
||||
}
|
||||
|
||||
func (w *Walker) walkPaths(paths *spec.Paths) *spec.Paths {
|
||||
if paths == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := paths
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
paths = &spec.Paths{}
|
||||
*paths = *orig
|
||||
}
|
||||
}
|
||||
|
||||
pathsCloned := false
|
||||
for k, v := range paths.Paths {
|
||||
if p := w.walkPathItem(&v); p != &v {
|
||||
if !pathsCloned {
|
||||
pathsCloned = true
|
||||
clone()
|
||||
paths.Paths = make(map[string]spec.PathItem, len(orig.Paths))
|
||||
for k2, v2 := range orig.Paths {
|
||||
paths.Paths[k2] = v2
|
||||
}
|
||||
}
|
||||
paths.Paths[k] = *p
|
||||
}
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
func (w *Walker) WalkRoot(swagger *spec.Swagger) *spec.Swagger {
|
||||
if swagger == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
orig := swagger
|
||||
cloned := false
|
||||
clone := func() {
|
||||
if !cloned {
|
||||
cloned = true
|
||||
swagger = &spec.Swagger{}
|
||||
*swagger = *orig
|
||||
}
|
||||
}
|
||||
|
||||
parametersCloned := false
|
||||
for k, v := range swagger.Parameters {
|
||||
if p := w.walkParameter(&v); p != &v {
|
||||
if !parametersCloned {
|
||||
parametersCloned = true
|
||||
clone()
|
||||
swagger.Parameters = make(map[string]spec.Parameter, len(orig.Parameters))
|
||||
for k2, v2 := range orig.Parameters {
|
||||
swagger.Parameters[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Parameters[k] = *p
|
||||
}
|
||||
}
|
||||
|
||||
responsesCloned := false
|
||||
for k, v := range swagger.Responses {
|
||||
if r := w.walkResponse(&v); r != &v {
|
||||
if !responsesCloned {
|
||||
responsesCloned = true
|
||||
clone()
|
||||
swagger.Responses = make(map[string]spec.Response, len(orig.Responses))
|
||||
for k2, v2 := range orig.Responses {
|
||||
swagger.Responses[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Responses[k] = *r
|
||||
}
|
||||
}
|
||||
|
||||
definitionsCloned := false
|
||||
for k, v := range swagger.Definitions {
|
||||
if s := w.WalkSchema(&v); s != &v {
|
||||
if !definitionsCloned {
|
||||
definitionsCloned = true
|
||||
clone()
|
||||
swagger.Definitions = make(spec.Definitions, len(orig.Definitions))
|
||||
for k2, v2 := range orig.Definitions {
|
||||
swagger.Definitions[k2] = v2
|
||||
}
|
||||
}
|
||||
swagger.Definitions[k] = *s
|
||||
}
|
||||
}
|
||||
|
||||
if swagger.Paths != nil {
|
||||
if p := w.walkPaths(swagger.Paths); p != swagger.Paths {
|
||||
clone()
|
||||
swagger.Paths = p
|
||||
}
|
||||
}
|
||||
|
||||
return swagger
|
||||
}
|
Reference in New Issue
Block a user